You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NextJS 13(App Router)如何用Zod验证请求头与URL参数?

解决NextJS 13 App Router中Zod验证请求头及URL参数的问题

一、修复请求头验证失败的问题

你当前验证失败的核心原因是:NextJS 13 App Router中req.headers是Headers类实例,并非普通JavaScript对象,Zod无法直接解析这种特殊结构。需要先将其转换为普通对象再验证。

修改后的验证代码如下:

import { z } from "zod";

export async function GET(req: Request) {
  // 将Headers实例转为普通对象,键会自动转为小写
  const headersObj = Object.fromEntries(req.headers.entries());

  const requestSchema = z.object({
    headers: z.object({
      // 确保这里的键是小写,因为请求头在传输中会被标准化为小写
      identifier: z.string().min(1, "identifier不能为空"),
    }),
  });

  const parsedRequest = requestSchema.safeParse({ headers: headersObj });

  if (!parsedRequest.success) {
    return new Response(
      JSON.stringify({
        errorCode: "badRequest",
        errors: parsedRequest.error.issues, // 可选:返回具体错误信息便于调试
      }),
      { status: 400 }
    );
  }

  // 验证通过后可正常使用解析后的请求头
  const { identifier } = parsedRequest.data.headers;
  // ...后续业务逻辑

  return new Response(JSON.stringify({ success: true, identifier }));
}

二、验证URL参数(路径参数+查询参数)

在App Router的API路由中,URL参数分为两种:路径参数(如/api/user/[id]中的id)和查询参数(如/api/user?id=123中的id),以下是两种参数的Zod验证方式:

1. 验证路径参数

假设你的路由文件是app/api/[userId]/route.ts,路径参数userId可以通过params参数获取:

import { z } from "zod";

// 定义路径参数的Zod Schema
const paramsSchema = z.object({
  userId: z.string().regex(/^\d+$/, "userId必须是数字字符串"),
});

export async function GET(req: Request, { params }: { params: { userId: string } }) {
  // 验证路径参数
  const parsedParams = paramsSchema.safeParse(params);
  if (!parsedParams.success) {
    return new Response(
      JSON.stringify({
        errorCode: "badRequest",
        errors: parsedParams.error.issues,
      }),
      { status: 400 }
    );
  }

  const { userId } = parsedParams.data;
  // ...后续业务逻辑
}

2. 验证查询参数

查询参数可以通过req.nextUrl.searchParams获取,同样需要转为普通对象后验证:

import { z } from "zod";

export async function GET(req: Request) {
  // 将查询参数转为普通对象
  const searchParamsObj = Object.fromEntries(req.nextUrl.searchParams.entries());

  // 定义查询参数的Zod Schema
  const searchParamsSchema = z.object({
    page: z.coerce.number().int().min(1).default(1), // 自动将字符串转为数字,默认值1
    size: z.coerce.number().int().min(1).max(100).default(10),
  });

  const parsedSearchParams = searchParamsSchema.safeParse(searchParamsObj);
  if (!parsedSearchParams.success) {
    return new Response(
      JSON.stringify({
        errorCode: "badRequest",
        errors: parsedSearchParams.error.issues,
      }),
      { status: 400 }
    );
  }

  const { page, size } = parsedSearchParams.data;
  // ...后续业务逻辑
}

三、组合验证(请求头+路径参数+查询参数)

如果需要同时验证多种参数,可以将多个Schema合并:

import { z } from "zod";

const requestSchema = z.object({
  headers: z.object({
    identifier: z.string().min(1),
  }),
  params: z.object({
    userId: z.string().regex(/^\d+$/),
  }),
  searchParams: z.object({
    page: z.coerce.number().int().min(1).default(1),
  }),
});

export async function GET(req: Request, { params }: { params: { userId: string } }) {
  const validationData = {
    headers: Object.fromEntries(req.headers.entries()),
    params,
    searchParams: Object.fromEntries(req.nextUrl.searchParams.entries()),
  };

  const parsedResult = requestSchema.safeParse(validationData);
  if (!parsedResult.success) {
    return new Response(
      JSON.stringify({
        errorCode: "badRequest",
        errors: parsedResult.error.issues,
      }),
      { status: 400 }
    );
  }

  // 解构所有验证通过的参数
  const { identifier } = parsedResult.data.headers;
  const { userId } = parsedResult.data.params;
  const { page } = parsedResult.data.searchParams;
  // ...后续业务逻辑
}

内容的提问来源于stack exchange,提问作者Craig Malton

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 02:57:49