
本文详解 Next.js App Router 中如何在 API Route(如 app/api/xxx/route.ts)正确返回响应(纯文本或 JSON),以及客户端如何可靠解析,彻底理清 Response、NextResponse.json()、res.text() 与 res.json() 的协作逻辑。
本文详解 next.js app router 中如何在 api route(如 `app/api/xxx/route.ts`)正确返回响应(纯文本或 json),以及客户端如何可靠解析,彻底理清 `response`、`nextresponse.json()`、`res.text()` 与 `res.json()` 的协作逻辑。
在 Next.js 13 引入 App Router 后,API Routes 迁移至 app/api/[name]/route.ts(或 .js),其处理方式与旧版 Pages Router 截然不同:不再基于 Express 风格的 req/res,而是遵循 Web Request/Response 标准,并推荐使用 NextResponse 工具类简化常见场景。许多开发者卡在“明明服务端写了数据,客户端却拿不到”——根源往往在于响应构造方式与客户端解析方法不匹配。
✅ 正确返回响应的两种主流方式
1. 返回纯文本(简单状态或字符串)
适用于轻量反馈(如成功提示、ID 回传等),无需 JSON 解析开销:
// app/api/dostuff/route.ts
export async function POST(request: Request) {
const { dataObj } = await request.json();
console.log('Received:', dataObj); // { hey: "ho" }
return new Response('Operation completed successfully', {
status: 200,
headers: { 'Content-Type': 'text/plain' },
});
}? 注意:new Response(...) 是原生 Web API,需手动设置 Content-Type;若省略,浏览器可能默认为 text/plain;charset=UTF-8,但显式声明更稳妥。
2. 返回结构化 JSON(推荐用于数据交互)
使用 NextResponse.json() —— 它自动设置 Content-Type: application/json 并序列化对象,语义清晰、不易出错:
// app/api/dostuff/route.ts
import { NextResponse } from 'next/server';
export async function POST(request: Request) {
const { dataObj } = await request.json();
// 业务逻辑处理...
const result = {
success: true,
message: 'Processed',
timestamp: new Date().toISOString()
};
return NextResponse.json(result, { status: 201 });
}✅ NextResponse.json() 内部已调用 JSON.stringify(),你无需也不应再手动包裹 JSON.stringify(result)。
? 客户端消费:按服务端类型选择对应解析方法
客户端必须与服务端响应格式严格对应。错误混用(如对 JSON 响应调用 .text())会导致数据类型异常或解析失败。
| 服务端返回方式 | 客户端解析方法 | 示例结果类型 |
|---|---|---|
| new Response('str') | await res.text() | string |
| NextResponse.json({...}) | await res.json() | any(建议配合 TypeScript 类型断言) |
// Client Component(如 app/page.tsx 或自定义 Hook)
'use client';
async function handleAction() {
try {
const res = await fetch('/api/dostuff', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ dataObj: { hey: 'ho' } }),
});
if (!res.ok) {
throw new Error(`HTTP error! status: ${res.status}`);
}
// ✅ 若服务端用 NextResponse.json() → 用 .json()
const data = await res.json(); // 类型:{ success: boolean; message: string; timestamp: string }
console.log(data.message); // "Processed"
// ❌ 错误示例(若服务端返回纯文本):
// const data = await res.json(); // 抛出 SyntaxError: Unexpected token O in JSON at position 0
} catch (error) {
console.error('API call failed:', error);
}
}⚠️ 关键注意事项与最佳实践
- 不要在服务端重复 JSON.stringify():NextResponse.json() 已完成序列化;若写成 NextResponse.json(JSON.stringify(obj)),会导致双重编码(如 "{"key":"val"}"),客户端 res.json() 将返回字符串而非对象。
- 始终检查 res.ok:网络请求成功 ≠ 业务成功。fetch 只在 HTTP 状态码为 4xx/5xx 时 reject,2xx/3xx 均进入 then,务必手动校验 res.ok 或 res.status。
-
TypeScript 类型安全建议:为 res.json() 添加泛型,提升开发体验:
interface ApiResponse { success: boolean; message: string; timestamp: string; } const data = await res.json() as ApiResponse; - 避免在 Server Components 中直接 fetch API Routes:App Router 的 Server Components 默认无 fetch 权限(除非是 fetch(..., { cache: 'no-store' }) 且部署在支持环境)。如需服务端调用,请改用 await fetch(...)(支持 RSC)或迁移至 Server Actions。
✅ 总结一句话
在 Next.js App Router 中:服务端用 NextResponse.json() 返回 JSON(自动序列化+头设置),客户端用 res.json() 解析;服务端用 new Response(text) 返回文本,客户端用 res.text() 获取——二者严格一一对应,即可彻底告别“JSON 混乱”。
掌握这一模式后,你将不再需要反复查阅文档,每一次 API Route 开发都变得清晰、可预测且健壮。










