Next.js 14 API Handler:如何正确验证Request JSON请求体?
我正在为开发中的iOS应用构建API,采用Next.js 14实现,大部分功能已正常运行,但对如何正确验证Request的请求体感到困惑。ESLint抛出了各类错误与警告,其中一个我尤为不确定:
Unsafe assignment of an any value
该警告出现在执行const body = await request.json();时。我明白此时json()方法返回any类型,但紧接着我就调用了validateRequest进行验证。我可以将其强制转换为RequestBody类型:const body = await request.json() as RequestBody;,但这似乎违背了验证的初衷,不是吗?请问有什么合适的处理方法吗?
代码示例:
// app/api/route.tsx interface RequestBody { name: string; } function validateRequest(object: any): object is RequestBody { return ( (object as RequestBody) && typeof (object as RequestBody).name === "string" ); } export async function POST(request: Request) { try { // Warning: Unsafe assignment of an `any` value const body = await request.json(); if (!validateRequest(body)) { return new Response("Invalid Data", { status: 400 }); } return Response.json({ message: body.name }); } catch { return new Response("Bad Request", { status: 400 }); } }
这里有几种既符合TypeScript类型安全要求,又不违背运行时验证初衷的处理方式:
1. 用unknown替代any声明请求体类型
request.json()返回any是ESLint警告的核心原因,改用unknown类型可以明确表示我们不确定请求体的结构,同时避免any带来的类型不安全问题。结合类型守卫后,TypeScript会自动在验证通过后推断出正确的类型:
// app/api/route.tsx interface RequestBody { name: string; } // 调整验证函数参数为unknown,逻辑更严谨 function validateRequest(object: unknown): object is RequestBody { return ( typeof object === 'object' && object !== null && 'name' in object && typeof (object as RequestBody).name === "string" ); } export async function POST(request: Request) { try { // 声明为unknown消除ESLint警告 const body: unknown = await request.json(); if (!validateRequest(body)) { return new Response("Invalid Data", { status: 400 }); } // 此时TypeScript已自动推断body为RequestBody类型 return Response.json({ message: body.name }); } catch { return new Response("Bad Request", { status: 400 }); } }
2. 类型断言配合中转(简易方案)
如果不想修改验证函数的参数类型,可以用unknown做中转,再临时断言为any用于验证阶段,这种方式适合快速调整:
export async function POST(request: Request) { try { const body = await request.json() as unknown; if (!validateRequest(body as any)) { return new Response("Invalid Data", { status: 400 }); } return Response.json({ message: (body as RequestBody).name }); } catch { return new Response("Bad Request", { status: 400 }); } }
3. 使用专业验证库(推荐)
手动编写类型守卫容易遗漏边界情况,使用Zod、Yup这类专门的运行时验证库,能同时实现TypeScript类型推导和严格的运行时校验,彻底解决类型安全和ESLint警告问题。以Zod为例:
import { z } from 'zod'; // 定义Zod校验规则,自动生成对应的TypeScript类型 const RequestBodySchema = z.object({ name: z.string(), }); type RequestBody = z.infer<typeof RequestBodySchema>; export async function POST(request: Request) { try { const body = await request.json(); // 验证请求体,不符合规则则直接抛出错误 const validatedBody = RequestBodySchema.parse(body); return Response.json({ message: validatedBody.name }); } catch (error) { return new Response("Invalid Data", { status: 400 }); } }
这种方式无需手动维护类型守卫,Zod会自动同步类型定义和校验逻辑,同时ESLint不会再抛出any相关警告。
内容的提问来源于stack exchange,提问作者SwiftedMind

