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

Next.js中GET API查询参数的最简推荐验证方案

Next.js API路由中验证GET查询参数的最佳实践

针对你提到的/pages/api/person/[id].ts场景,下面分点给出实用的验证方案,兼顾简洁性与安全性:

一、单个数字ID的极简验证(无需依赖库)

直接用原生JS/TS做运行时验证是最轻量化的方案,但要注意避免isNaN的坑——isNaN('')、isNaN(true)会返回false,导致误判。正确的做法是结合类型检查和整数判断:

import type { NextApiRequest, NextApiResponse } from 'next';

export default function handler(req: NextApiRequest, res: NextApiResponse) {
  const { id } = req.query;
  
  // 处理Next.js中参数可能为数组的情况(如重复传?id=1&id=2)
  const rawId = Array.isArray(id) ? id[0] : id;
  
  // 1. 检查参数是否存在且为字符串
  if (!rawId || typeof rawId !== 'string') {
    return res.status(400).json({ error: 'ID参数缺失或格式错误' });
  }
  
  // 2. 转换为数字并验证是否为正整数
  const numericId = Number(rawId);
  if (!Number.isInteger(numericId) || numericId <= 0) {
    return res.status(400).json({ error: 'ID必须为正整数' });
  }
  
  // 后续逻辑:用numericId查询Prisma等
  res.status(200).json({ id: numericId });
}

二、Next.js是否支持路径正则约束?

很遗憾,不管是Pages Router还是App Router,Next.js都没有在路由定义中直接添加正则规则的官方支持。所有参数验证逻辑必须在API handler内部完成。

三、TypeScript的辅助作用

TypeScript是静态类型检查,无法替代运行时验证(因为req.query的类型本质是ParsedUrlQuery,运行时仍可能是任意类型),但可以通过自定义类型守卫让TS自动推断验证后的参数类型:

// 自定义类型守卫函数
function isValidPositiveInteger(id: unknown): id is number {
  if (typeof id !== 'string') return false;
  const num = Number(id);
  return Number.isInteger(num) && num > 0;
}

// 在handler中使用
export default function handler(req: NextApiRequest, res: NextApiResponse) {
  const { id } = req.query;
  
  if (!isValidPositiveInteger(id)) {
    return res.status(400).json({ error: '无效的ID格式' });
  }
  
  // 此处id会被TS自动推断为number类型
  console.log(id.toFixed(0)); // 无类型报错
}

四、验证库是否大材小用?

如果只是单个参数,用ajv/joi/yup确实有点过重,但Zod是个例外——它的API极简,单个schema的代码量极少,同时还能提供类型安全:

import { z } from 'zod';
import type { NextApiRequest, NextApiResponse } from 'next';

// 定义单个参数的验证规则
const PersonIdSchema = z.string()
  .transform(val => Number(val)) // 自动转换为数字
  .pipe(z.number().int().positive()); // 验证正整数

export default function handler(req: NextApiRequest, res: NextApiResponse) {
  try {
    // 验证并转换参数
    const id = PersonIdSchema.parse(req.query.id);
    // 后续逻辑:id已被确保为正整数,且TS能推断其类型
    res.status(200).json({ id });
  } catch (err) {
    res.status(400).json({ error: '无效的ID格式' });
  }
}

Zod的优势在于,当后续API需要验证多个参数(如分页参数page/limit)时,扩展成本极低,同时保持类型安全,属于“一次投入,长期受益”的方案。

五、能否直接将参数传入Prisma?

虽然Prisma会自动做参数化查询,避免SQL注入风险,但不建议直接传入未验证的参数:

  1. 无效参数(如非数字ID)会导致Prisma返回空结果或抛出数据库级错误,返回给前端的错误信息不够友好;
  2. 提前拦截无效请求能减少不必要的数据库查询,提升性能;
  3. 若后续需要将ID渲染到页面,未验证的参数可能带来XSS风险(虽然GET参数用于查询时风险较低,但提前验证是良好习惯)。

总结推荐

  • 单个简单参数:用原生验证+类型守卫,最简洁;
  • 多参数/复杂场景:用Zod,兼顾简洁性与类型安全;
  • 必须坚持运行时验证,TS仅作为辅助工具;
  • 不要跳过参数验证直接传入数据库,即使有ORM防护。

内容的提问来源于stack exchange,提问作者polak polkovski

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 07:01:16