前言
大家好,我是鲫小鱼。是一名不写前端代码
的前端工程师,热衷于分享非前端的知识,带领切图仔逃离切图圈子,欢迎关注我,微信公众号:《鲫小鱼不正经》
。欢迎点赞、收藏、关注,一键三连!!
第十二章 API Routes:构建轻量级后端服务
一、理论讲解
1. API Routes 的原理
API Routes 是 Next.js 提供的内置后端能力,允许你在 pages/api 目录下直接编写 Node.js 风格的 API 接口。每个文件自动映射为一个 HTTP 路由,无需额外配置。
- 文件系统路由:如 pages/api/user.ts 自动映射为 /api/user。
- 与传统后端区别:无需单独部署后端服务,前后端同构,开发体验极佳。
- 支持多种 HTTP 方法:GET、POST、PUT、DELETE、PATCH 等。
- 请求体解析:自动解析 JSON、表单、multipart 等。
- 与 App Router/Server Actions 的关系:API Routes 适合 RESTful/文件上传/第三方集成,Server Actions 适合表单、组件内服务端逻辑。
API Routes 文件结构与路由映射
text
/pages/api/
user.ts -> /api/user
posts/[id].ts -> /api/posts/123
支持的 HTTP 方法
API Routes 通过 req.method 区分不同请求类型。
ts
export default function handler(req, res) {
if (req.method === 'GET') { /* 查询 */ }
if (req.method === 'POST') { /* 新增 */ }
if (req.method === 'PUT') { /* 更新 */ }
if (req.method === 'DELETE') { /* 删除 */ }
}
请求体解析
- JSON 自动解析为 req.body
- multipart/form-data 需自定义解析(如用 formidable)
API 中间件
可自定义中间件实现日志、权限、CORS、限流等。
ts
function withAuth(handler) {
return (req, res) => {
if (!req.headers['x-token']) return res.status(401).json({ message: '未授权' });
return handler(req, res);
};
}
export default withAuth((req, res) => { /* ... */ });
权限校验
- 建议所有敏感 API 均做 token/session 校验
- 可结合 JWT、Session、OAuth 等
文件上传
- 需关闭 bodyParser,使用第三方库(如 formidable、multer)解析文件流
ts
// pages/api/upload.ts
import formidable from 'formidable';
export const config = { api: { bodyParser: false } };
export default function handler(req, res) {
const form = new formidable.IncomingForm();
form.parse(req, (err, fields, files) => {
if (err) return res.status(500).json({ message: '上传失败' });
// 处理 files
res.json({ url: '/uploads/' + files.file.newFilename });
});
}
流式响应
- 可用 res.write/res.end 实现大文件下载、实时推送
ts
export default function handler(req, res) {
res.setHeader('Content-Type', 'text/plain');
res.write('Hello, ');
setTimeout(() => {
res.write('World!');
res.end();
}, 1000);
}
常见误区
- 忽略权限校验,易被攻击
- 忽略 CORS,导致跨域失败
- 请求体过大未限制,易被刷爆
- 错误处理不规范,影响前端体验
二、代码示例
1. 多种 HTTP 方法的 API
ts
// pages/api/todo.ts
let todos = [];
export default function handler(req, res) {
if (req.method === 'GET') return res.json(todos);
if (req.method === 'POST') {
const { text } = req.body;
todos.push({ id: Date.now(), text });
return res.status(201).json({ success: true });
}
if (req.method === 'DELETE') {
const { id } = req.body;
todos = todos.filter(t => t.id !== id);
return res.json({ success: true });
}
res.status(405).end();
}
2. Zod 校验参数
ts
import { z } from 'zod';
const schema = z.object({ text: z.string().min(1) });
export default function handler(req, res) {
if (req.method === 'POST') {
const result = schema.safeParse(req.body);
if (!result.success) return res.status(400).json({ error: result.error.errors });
// ...业务逻辑
}
}
3. 文件上传
ts
// pages/api/upload.ts
import formidable from 'formidable';
export const config = { api: { bodyParser: false } };
export default function handler(req, res) {
const form = new formidable.IncomingForm();
form.parse(req, (err, fields, files) => {
if (err) return res.status(500).json({ message: '上传失败' });
res.json({ url: '/uploads/' + files.file.newFilename });
});
}
4. 流式响应
ts
export default function handler(req, res) {
res.setHeader('Content-Type', 'text/plain');
res.write('Hello, ');
setTimeout(() => {
res.write('World!');
res.end();
}, 1000);
}
5. API 路由安全与错误处理
ts
function withAuth(handler) {
return (req, res) => {
if (!req.headers['x-token']) return res.status(401).json({ message: '未授权' });
return handler(req, res);
};
}
export default withAuth((req, res) => {
try {
// ...业务逻辑
} catch (err) {
res.status(500).json({ message: '服务异常' });
}
});
6. 移动端适配与 API 日志埋点
js
// pages/api/log.ts
export default function handler(req, res) {
const { event, userAgent } = req.body;
// 记录日志
res.json({ success: true });
}
三、实战项目:图片分享应用 API 设计
1. 项目需求
- 支持图片上传、图片列表获取
- 文件存储可本地或模拟
- 权限校验,防止未授权上传
- 错误兜底、性能监控、移动端友好
2. 技术选型
- Next.js API Routes
- formidable 文件上传
- JWT/Token 权限校验
- Sentry/自研埋点
3. 目录结构
text
/pic-share-demo
|-- pages/
|-- api/
|-- upload.ts
|-- images.ts
|-- log.ts
|-- uploads/
|-- components/
|-- UploadForm.tsx
|-- ImageList.tsx
|-- styles/
|-- globals.css
4. 图片上传 API
ts
// pages/api/upload.ts
import formidable from 'formidable';
export const config = { api: { bodyParser: false } };
function withAuth(handler) {
return (req, res) => {
if (!req.headers['x-token']) return res.status(401).json({ message: '未授权' });
return handler(req, res);
};
}
export default withAuth(function handler(req, res) {
const form = new formidable.IncomingForm({ uploadDir: './uploads', keepExtensions: true });
form.parse(req, (err, fields, files) => {
if (err) return res.status(500).json({ message: '上传失败' });
res.json({ url: '/uploads/' + files.file.newFilename });
});
});
5. 图片列表 API
ts
// pages/api/images.ts
import fs from 'fs';
export default function handler(req, res) {
const files = fs.readdirSync('./uploads');
res.json({ images: files.map(f => '/uploads/' + f) });
}
6. 错误兜底与性能监控
js
// pages/api/log.ts
export default function handler(req, res) {
const { event, userAgent } = req.body;
// 上报日志
res.json({ success: true });
}
四、最佳实践
- API 设计规范:RESTful 路径、动词明确、状态码规范。
- 参数校验:用 Zod/Joi 校验所有输入,防止脏数据。
ts
import { z } from 'zod';
const schema = z.object({ text: z.string().min(1) });
const result = schema.safeParse(req.body);
if (!result.success) return res.status(400).json({ error: result.error.errors });
- 权限安全:所有敏感操作都要鉴权。
- 错误处理:try/catch 包裹业务逻辑,返回规范错误。
- 团队协作:接口文档同步、mock 数据、自动化测试。
- 监控报警:API 异常自动上报。
- 极端场景降级:接口超时、上传失败时前端兜底提示。
tsx
if (error) return <div>图片上传失败,请稍后重试</div>;
五、常见问题与解决方案
- Q: 跨域(CORS)问题?
- A: 设置响应头
res.setHeader('Access-Control-Allow-Origin', '*')
,或用中间件统一处理。
- A: 设置响应头
- Q: 请求体过大?
- A: 限制文件大小,formidable/multer 支持 maxFileSize。
- Q: 文件上传失败?
- A: 检查目录权限、磁盘空间、bodyParser 配置。
- Q: 权限绕过?
- A: 所有敏感 API 都要鉴权,token/session 校验。
- Q: API 性能瓶颈?
- A: 静态资源用 CDN,接口限流,异步处理。
- Q: 接口幂等性?
- A: 关键操作加唯一标识,防止重复提交。
最后感谢阅读!欢迎关注我,微信公众号:
《鲫小鱼不正经》
。欢迎点赞、收藏、关注,一键三连!!!