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: 关键操作加唯一标识,防止重复提交。

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

相关推荐
lovingsoft25 分钟前
Chrome Lighthouse 详解
前端·chrome
Qlly35 分钟前
全栈工程师怎么接需求?从一句「加个功能」聊到能开发、能验收
前端·后端
马可家的菠萝39 分钟前
你的微信“文件传输助手”,是不是已经成了第二个网盘?
前端·后端·架构
略略略啦40 分钟前
Vibe Coding 基于Spec DD和TDD的实践指南
前端
shmily麻瓜小菜鸡1 小时前
前端实现图片与PDF文字识别敏感信息打码方案
前端·pdf·状态模式
打工仔折腾 AI1 小时前
LangChain 工具调用实战:从 Tool 定义到 Agent 执行链路拆解
java·前端·人工智能·后端·python·langchain·ai agent 实战
汉堡大王95271 小时前
单次输出拉到100万Token:拆完 Gemini 4 Argon 的续写协议,才看懂谷歌这7个月在憋什么
前端·人工智能·后端
看浪的路人1 小时前
第9讲:大模型应用监控与可观测性——OpenTelemetry + Prometheus + Grafana 全链路追踪
java·前端·spring
内存过载1 小时前
用表格模拟甘特图:项目排期的土办法
前端·低代码
葡萄城技术团队2 小时前
用 SpreadJS 数据验证实现省市区三级联动
前端