Next.js中GET接口获取JSON请求体触发500错误的问题
问题:Next.js GET接口调用request.json()返回500错误
我写了下面这个Next.js API接口,只要加上const rawRequest = await request.json();这一行,接口就返回500状态码。试过重装依赖、升级Next.js到最新版、重启服务器,都没用。想问下GET请求是不是不能带请求体?
import { NextResponse } from "next/server"; import z from "zod"; import { Review, User, } from "@/mongo"; import { findReview } from "@/mongo/functions/review"; export async function GET (request: Request) { const rawRequest = await request.json(); const Schema = z.object ({ id: z.string().optional(), filters: z.any().optional(), }).strict() const parsedRequest: RequestType = rawRequest.body; const valid = Schema.safeParse(parsedRequest); type RequestType = z.infer<typeof Schema>; if (!valid.success) { return NextResponse.json( { message: `Error: ${valid.error}` }, { status: 400 } ); } try { const reviews = await findReview ({}) return NextResponse.json ({reviews}) } catch (error) { return NextResponse.json ({message: `Error: ${error}`}) } } export async function POST (request: Request) { const rawRequest = await request.json(); const statusOptions = { unlisted: "unlisted", public: "public", } as const const Schema = z.object({ title: z.string().min(5).max(20), text: z.string().min(10).max(1000), stars: z.number().gte(1).lte(5), type: z.string(), status: z.nativeEnum(statusOptions), author: z.string(), recipient: z.string().min(5), }); const parsedRequest: RequestType = rawRequest.body; const valid = Schema.safeParse(parsedRequest); type RequestType = z.infer<typeof Schema>; if (!valid.success) { return NextResponse.json( { message: `Error: ${valid.error}` }, { status: 400 } ); } let isCustomer = false; if (parsedRequest.type === "customer") { isCustomer = true; } try { await Review.create ({ title: parsedRequest.title, text: parsedRequest.text, stars: parsedRequest.stars, isReviewOnCustomer: isCustomer, author: parsedRequest.author, recipient: parsedRequest.recipient, status: parsedRequest.status, }) const allReviews = await Review.find({recipient: parsedRequest.recipient}); const stars: number[] = [] allReviews.forEach(review => { stars.push(review.stars) }) let total = 0; for(let i = 0; i < stars.length; i++) { total += stars[i]; } const avg = total / stars.length; if (isCustomer) { await User.updateOne ({_id: parsedRequest.recipient}, {customerRating: avg}) } else { await User.updateOne ({userId: parsedRequest.recipient}, {businessRating: avg}) } return NextResponse.json({ message: "Successfully added a review" }); } catch (error) { return NextResponse.json({ message: `Error: ${error}` }, { status: 500 }); } }
错误信息
⨯ SyntaxError: Unexpected end of JSON input at JSON.parse (<anonymous>) at parseJSONFromBytes (node:internal/deps/undici/undici:6662:19) at successSteps (node:internal/deps/undici/undici:6636:27) at specConsumeBody (node:internal/deps/undici/undici:6642:9) at NextRequest.json (node:internal/deps/undici/undici:6533:18) at GET (webpack-internal:///(rsc)/./app/api/reviews/add/route.ts:15:38) at /Users/ekrich/git/commerce-karma-prod/node_modules/next/dist/compiled/next-server/app-route.runtime.dev.js:6:62597 at /Users/ekrich/git/commerce-karma-prod/node_modules/next/dist/server/lib/trace/tracer.js:131:36 at NoopContextManager.with (/Users/ekrich/git/commerce-karma-prod/node_modules/next/dist/compiled/@opentelemetry/api/index.js:1:7062) at ContextAPI.with (/Users/ekrich/git/commerce-karma-prod/node_modules/next/dist/compiled/@opentelemetry/api/index.js:1:518) at NoopTracer.startActiveSpan (/Users/ekrich/git/commerce-karma-prod/node_modules/next/dist/compiled/@opentelemetry/api/index.js:1:18093) at ProxyTracer.startActiveSpan (/Users/ekrich/git/commerce-karma-prod/node_modules/next/dist/compiled/@opentelemetry/api/index.js:1:18854) at /Users/ekrich/git/commerce-karma-prod/node_modules/next/dist/server/lib/trace/tracer.js:120:103 at NoopContextManager.with (/Users/ekrich/git/commerce-karma-prod/node_modules/next/dist/compiled/@opentelemetry/api/index.js:1:7062) at ContextAPI.with (/Users/ekrich/git/commerce-karma-prod/node_modules/next/dist/compiled/@opentelemetry/api/index.js:1:518) at NextTracerImpl.trace (/Users/ekrich/git/commerce-karma-prod/node_modules/next/dist/server/lib/trace/tracer.js:120:28) at /Users/ekrich/git/commerce-karma-prod/node_modules/next/dist/compiled/next-server/app-route.runtime.dev.js:6:56181 at AsyncLocalStorage.run (node:async_hooks:346:14) at Object.wrap (/Users/ekrich/git/commerce-karma-prod/node_modules/next/dist/compiled/next-server/app-route.runtime.dev.js:6:36760) at /Users/ekrich/git/commerce-karma-prod/node_modules/next/dist/compiled/next-server/app-route.runtime.dev.js:6:53968 at AsyncLocalStorage.run (node:async_hooks:346:14) at Object.wrap (/Users/ekrich/git/commerce-karma-prod/node_modules/next/dist/compiled/next-server/app-route.runtime.dev.js:6:36288) at /Users/ekrich/git/commerce-karma-prod/node_modules/next/dist/compiled/next-server/app-route.runtime.dev.js:6:53930 at AsyncLocalStorage.run (node:async_hooks:346:14) at eI.execute (/Users/ekrich/git/commerce-karma-prod/node_modules/next/dist/compiled/next-server/app-route.runtime.dev.js:6:53904) at eI.handle (/Users/ekrich/git/commerce-karma-prod/node_modules/next/dist/compiled/next-server/app-route.runtime.dev.js:6:63840) at doRender (/Users/ekrich/git/commerce-karma-prod/node_modules/next/dist/server/base-server.js:1332:60) at cacheEntry.responseCache.get.routeKind (/Users/ekrich/git/commerce-karma-prod/node_modules/next/dist/server/base-server.js:1571:34) at ResponseCache.get (/Users/ekrich/git/commerce-karma-prod/node_modules/next/dist/server/response-cache/index.js:54:26) at DevServer.renderToResponseWithComponentsImpl (/Users/ekrich/git/commerce-karma-prod/node_modules/next/dist/server/base-server.js:1479:53) at /Users/ekrich/git/commerce-karma-prod/node_modules/next/dist/server/base-server.js:983:121 at NextTracerImpl.trace (/Users/ekrich/git/commerce-karma-prod/node_modules/next/dist/server/lib/trace/tracer.js:102:20) at DevServer.renderToResponseWithComponents (/Users/ekrich/git/commerce-karma-prod/node_modules/next/dist/server/base-server.js:983:41) at DevServer.renderPageComponent (/Users/ekrich/git/commerce-karma-prod/node_modules/next/dist/server/base-server.js:1850:35) at async DevServer.renderToResponseImpl (/Users/ekrich/git/commerce-karma-prod/node_modules/next/dist/server/base-server.js:1888:32) at async DevServer.pipeImpl (/Users/ekrich/git/commerce-karma-prod/node_modules/next/dist/server/base-server.js:902:25) at async NextNodeServer.handleCatchallRenderRequest (/Users/ekrich/git/commerce-karma-prod/node_modules/next/dist/server/next-server.js:266:17)
解答
GET请求不应该带请求体
虽然HTTP规范没有完全禁止GET请求带请求体,但绝大多数客户端、服务器和中间件都不支持这种做法,Next.js的request.json()在处理没有请求体的GET请求时,就会抛出你看到的Unexpected end of JSON input错误——因为根本没有JSON数据可以解析。修复方案
如果你需要传递参数给GET接口,应该用URL查询参数或者路由参数,而不是请求体:
修改后的GET接口代码
export async function GET(request: Request) { // 解析URL查询参数 const { searchParams } = new URL(request.url); const parsedRequest = { id: searchParams.get("id") || undefined, filters: searchParams.get("filters") ? JSON.parse(searchParams.get("filters")!) : undefined }; const Schema = z.object({ id: z.string().optional(), filters: z.any().optional(), }).strict(); const valid = Schema.safeParse(parsedRequest); if (!valid.success) { return NextResponse.json( { message: `Error: ${valid.error}` }, { status: 400 } ); } try { // 把解析后的参数传给findReview const reviews = await findReview(parsedRequest); return NextResponse.json({ reviews }); } catch (error) { return NextResponse.json({ message: `Error: ${error}` }); } }
- 额外问题修复
另外你的代码里还有个小问题:不管是GET还是POST接口,request.json()返回的就是请求体本身,不需要再取rawRequest.body——await request.json()直接得到的就是POST请求发送的JSON对象,所以POST接口里的const parsedRequest: RequestType = rawRequest.body;应该改成const parsedRequest: RequestType = rawRequest;,不然会拿到undefined导致验证失败。
内容的提问来源于stack exchange,提问作者Ethan
相关产品推荐
相关产品推荐

