Next.js 教程系列(十二)API Routes:构建轻量级后端服务

前言

大家好,我是鲫小鱼。是一名不写前端代码的前端工程师,热衷于分享非前端的知识,带领切图仔逃离切图圈子,欢迎关注我,微信公众号:《鲫小鱼不正经》。欢迎点赞、收藏、关注,一键三连!!


第十二章 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 });
}

四、最佳实践

  1. API 设计规范:RESTful 路径、动词明确、状态码规范。
  2. 参数校验:用 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 });
  1. 权限安全:所有敏感操作都要鉴权。
  2. 错误处理:try/catch 包裹业务逻辑,返回规范错误。
  3. 团队协作:接口文档同步、mock 数据、自动化测试。
  4. 监控报警:API 异常自动上报。
  5. 极端场景降级:接口超时、上传失败时前端兜底提示。
tsx 复制代码
if (error) return <div>图片上传失败,请稍后重试</div>;

五、常见问题与解决方案

  • Q: 跨域(CORS)问题?
    • A: 设置响应头 res.setHeader('Access-Control-Allow-Origin', '*'),或用中间件统一处理。
  • Q: 请求体过大?
    • A: 限制文件大小,formidable/multer 支持 maxFileSize。
  • Q: 文件上传失败?
    • A: 检查目录权限、磁盘空间、bodyParser 配置。
  • Q: 权限绕过?
    • A: 所有敏感 API 都要鉴权,token/session 校验。
  • Q: API 性能瓶颈?
    • A: 静态资源用 CDN,接口限流,异步处理。
  • Q: 接口幂等性?
    • A: 关键操作加唯一标识,防止重复提交。

最后感谢阅读!欢迎关注我,微信公众号:《鲫小鱼不正经》。欢迎点赞、收藏、关注,一键三连!!!

相关推荐
我要让全世界知道我很低调2 分钟前
记一次 Vite 下的白屏优化
前端·css
1undefined24 分钟前
element中的Table改造成虚拟列表,并封装成hooks
前端·javascript·vue.js
蓝倾39 分钟前
淘宝批量获取商品SKU实战案例
前端·后端·api
comelong44 分钟前
Docker容器启动postgres端口映射失败问题
前端
花海如潮淹1 小时前
硬件产品研发管理工具实战指南
前端·python
用户3802258598241 小时前
vue3源码解析:依赖收集
前端·vue.js
WaiterL1 小时前
一文读懂 MCP 与 Agent
前端·人工智能·cursor
gzzeason1 小时前
使用Vite创建React初始化项目
前端·javascript·react.js
又双叒叕7781 小时前
React19 新增Hooks:useOptimistic
前端·javascript·react.js
归于尽1 小时前
V8 引擎是如何给 JS"打扫房间"的 ?
前端·javascript