测试 Next.js 应用路由器的 API 路由 - Arcjet 博客
关于软件安全的一大乐趣在于探索那些令人惊叹且复杂的攻击方法。例如,谷歌的 Project Zero 曾对一个在 iOS PDF 渲染组件中的假 GIF 文件中实现的图灵完备 CPU 进行分析,这个漏洞被用于开发 iMessage 的零点击攻击。这种复杂性让人叹为观止!
尽管这些漏洞很有趣,但普通用户通常不会受到这些复杂攻击的影响。实际上,大多数攻击往往是利用一些简单的安全漏洞,比如默认密码、过时软件中的已知问题或代码中的逻辑错误。这些问题在开发阶段可能难以发现,但在渗透测试中却经常暴露。然而,通过编写测试来验证代码的预期行为,可以有效避免这些问题随着代码的演变而产生回归。
测试 Next.js API 路由处理程序的挑战
在 Next.js 中测试 API 路由处理程序并非易事。官方文档主要关注前端组件的测试,而深入到 API 路由的测试时,你会发现并没有现成的解决方案。
Next.js 已经采用了 TypeScript 5.2+ 中的标准请求和响应类型,但同时也扩展了 NextRequest 和 NextResponse 类型。此外,Next.js 对全局 fetch 函数进行了修补,增加了自定义 API 来访问头部信息或 Cookie,支持可选的段配置,并提供不同的运行时环境。
为了测试这些路由,你需要模拟自己的库,并启动一个服务器来发出请求。有些开发者尝试使用 node-mocks-http 来实现这一点,但并非总是成功。如果需要测试 Edge 运行时,问题会变得更加复杂。
如何测试 Next.js API 路由处理程序
幸运的是,next-test-api-route-handler 包解决了大部分问题。它与测试框架无关,可以模拟 Next.js 的应用路由器、页面路由器以及 Edge 运行时。
以下是一个基本的配置示例:
// jest.config.ts
import type { Config } from 'jest';
import nextJest from 'next/jest';
const createJestConfig = nextJest({
dir: './', // 指定 Next.js 应用的路径
});
const config: Config = {
coverageProvider: 'v8',
testEnvironment: 'node',
moduleNameMapper: {
'^@/(.*)$': '/$1',
},
setupFilesAfterEnv: ['./jest.setup.ts'],
};
export default createJestConfig(config);
// jest.setup.ts
import '@testing-library/jest-dom';
// app/api/hello/route.ts
import { NextResponse } from 'next/server';
export async function GET(request: Request) {
return NextResponse.json({ hello: true }, { status: 200 });
}
// app/api/hello/route.test.ts
import { testApiHandler } from 'next-test-api-route-handler';
import * as appHandler from './route';
it('GET 返回 200', async () => {
await testApiHandler({
handler: appHandler,
test: async ({ fetch }) => {
const response = await fetch({ method: 'GET' });
const json = await response.json();
expect(response.status).toBe(200);
expect(json).toStrictEqual({ hello: true });
},
});
});
运行 jest 命令即可执行测试。
模拟身份验证并测试经过身份验证的路由
以下是一个带有身份验证的 API 路由示例:
// app/api/hello/route.ts
import { authOptions } from '@/lib/auth';
import { getServerSession } from 'next-auth/next';
import { NextResponse } from 'next/server';
export async function GET(request: Request) {
const session = await getServerSession(authOptions);
if (!session || !session.user) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
return NextResponse.json({ hello: true }, { status: 200 });
}
为了测试该路由,我们需要模拟 getServerSession 的调用:
// app/api/hello/route.test.ts
import { testApiHandler } from 'next-test-api-route-handler';
import type { Session } from 'next-auth';
import * as appHandler from './route';
let mockedSession: Session | null = null;
jest.mock('@/lib/auth', () => ({
authOptions: { adapter: {}, providers: [], callbacks: {} },
}));
jest.mock('next-auth/next', () => ({
getServerSession: jest.fn(() => Promise.resolve(mockedSession)),
}));
afterEach(() => {
mockedSession = null;
});
it('未经身份验证时,GET 返回 401', async () => {
mockedSession = null;
await testApiHandler({
handler: appHandler,
test: async ({ fetch }) => {
const response = await fetch({ method: 'GET' });
const json = await response.json();
expect(response.status).toBe(401);
expect(json).toStrictEqual({ error: 'Unauthorized' });
},
});
});
it('通过身份验证时,GET 返回 200', async () => {
mockedSession = { expires: 'expires', user: { id: 'test' } };
await testApiHandler({
handler: appHandler,
test: async ({ fetch }) => {
const response = await fetch({ method: 'GET' });
const json = await response.json();
expect(response.status).toBe(200);
expect(json).toStrictEqual({ hello: true });
},
});
});
结论
通过以上方法,你可以轻松测试 Next.js 的 API 路由,包括模拟数据库调用、拆分模拟文件以及测试授权逻辑(例如用户是否有权限访问特定数据)。这些基础设置可以帮助你确保敏感的 API 路由在代码更改后依然安全可靠。
原文链接: https://blog.arcjet.com/testing-next-js-app-router-api-routes/
最新文章
- OWASP API十大漏洞及DAST如何保护您 …
- API安全在物联网(IoT)中的关键作用
- Java后端API接口开发规范
- PyJWT:轻松搞定Token认证,让你的API更安全!
- 2025年7月GitHub 上热门的10大API开源项目
- 构建远程医疗应用的10个最佳Telehealth API选项
- 使用 FastAPI、Docker 和 Hugging Face Transformers 的文本分类 API
- IdeaGitLab 插件API Token is not valid解决方案
- API架构设计基础
- 什么是GPT-4?完整指南
- 最佳API测试工具:REST和SOAP自动化 – Parasoft
- 如何使用Ollama(完整Ollama速查表)- Apidog