第17章 API Routes
Next.js 后端 API 开发入门
作者:zyyc-0336 | 日期:2026-06-12
17.1 前端也能写接口?
传统开发中,前端负责页面,后端负责接口(API)。但 Next.js 让你在同一个项目里写出接口,不用单独搭一个后端服务器。
API Route 是什么?
简单说,它就是一个 URL 地址,当前端访问这个地址时,服务器会执行一段代码并返回数据。
前端页面: /articles/hello → 返回 HTML 页面
API Route:/api/comments → 返回 JSON 数据
💡 通俗理解:页面是给用户看的,API 是给程序用的。API 返回的是纯数据(JSON),不是网页。
17.2 和传统后端的区别
| 对比项 | 传统后端(Express/Koa) | Next.js API Route |
|---|---|---|
| 需要单独的项目? | 是 | 不用,和前端同项目 |
| 需要配服务器? | 是 | 不用,Next.js 自带 |
| 独立部署? | 是 | 和前端一起部署 |
| 适合场景 | 复杂后端逻辑 | 简单接口、快速原型 |
💡 如果你的接口逻辑很复杂(比如需要连接多种数据库、处理消息队列),建议用独立后端。如果只是简单的 CRUD 操作,API Route 完全够用。
17.3 文件结构
在 Next.js 的 App Router 中,API Route 就是一个放在
app/ 目录下的 route.js 文件:src/app/
├── page.js # 首页
├── layout.js # 布局
└── api/
└── hello/
└── route.js # → 对应 /api/hello
⚠️ 注意:文件名必须是
route.js(或 route.ts),不能是 index.js 或其他名字。17.4 GET 请求示例
// src/app/api/hello/route.js
import { NextResponse } from 'next/server'
// 处理 GET 请求
export async function GET() {
return NextResponse.json({
message: 'Hello, API!',
time: new Date().toLocaleString()
})
}
代码解读
| 代码 | 含义 |
|---|---|
export async function GET() | 导出一个叫 GET 的异步函数,处理 GET 请求 |
NextResponse.json({...}) | 返回一个 JSON 格式的响应 |
new Date().toLocaleString() | 获取当前时间 |
💡
GET 函数名必须全大写,它对应 HTTP 的 GET 方法。Next.js 会根据文件路径自动映射 URL。17.5 测试接口
启动开发服务器后,打开浏览器访问:
http://localhost:3000/api/hello
你应该看到:
{
"message": "Hello, API!",
"time": "2026/6/12 14:30:00"
}
💡 测试 API 也可以用
curl 命令:curl http://localhost:3000/api/hello17.6 接收 JSON 数据
当前端用 POST 方法提交 JSON 数据时,需要用
await request.json() 来获取:export async function POST(request) {
// 注意:json() 是异步的,必须加 await
const body = await request.json()
console.log('收到的数据:', body)
return NextResponse.json({
success: true,
received: body
})
}
⚠️
request.json() 返回的是 Promise,必须加 await,否则你拿到的是一个 Promise 对象,不是实际数据。17.7 完整示例:评论接口
// src/app/api/comments/route.js
import { NextResponse } from 'next/server'
// 模拟数据库(用数组存储)
const comments = [
{ id: 1, user: '小明', content: '写得不错!', time: '2026-06-10' },
{ id: 2, user: '小红', content: '学到了!', time: '2026-06-11' }
]
// GET:获取所有评论
export async function GET() {
return NextResponse.json({
success: true,
data: comments
})
}
// POST:添加新评论
export async function POST(request) {
const body = await request.json()
// 简单验证
if (!body.user || !body.content) {
return NextResponse.json(
{ success: false, message: '用户名和评论内容不能为空' },
{ status: 400 }
)
}
// 创建新评论
const newComment = {
id: comments.length + 1,
user: body.user,
content: body.content,
time: new Date().toISOString().split('T')[0]
}
comments.push(newComment)
return NextResponse.json({
success: true,
data: newComment,
message: '评论成功!'
}, { status: 201 })
}
代码解读
| 部分 | 含义 |
|---|---|
const comments = [...] | 模拟数据库,实际项目会用数据库 |
if (!body.user || !body.content) | 验证必填字段 |
NextResponse.json({...}, { status: 400 }) | 返回错误状态码 |
{ status: 201 } | 201 表示"已创建",是 POST 成功的标准状态码 |
17.8 NextRequest 的常用方法
request 参数是一个 NextRequest 对象,它比原生的 Request 多了很多实用方法:export async function GET(request) {
// 获取 URL 查询参数
const name = request.nextUrl.searchParams.get('name')
// 获取请求头
const userAgent = request.headers.get('user-agent')
// 获取 cookies
const token = request.cookies.get('token')
// 获取完整 URL
const url = request.nextUrl.href
return NextResponse.json({ name, userAgent, url })
}
常用属性/方法速查
| 方法 | 作用 | 示例 |
|---|---|---|
request.nextUrl.searchParams | 获取 URL 查询参数 | /api/hello?name=小明 → get('name') = '小明' |
request.headers | 获取请求头 | headers.get('content-type') |
request.cookies | 获取 Cookie | cookies.get('token') |
request.json() | 获取 POST 的 JSON 数据 | await request.json() |
request.method | 获取请求方法 | 'GET'、'POST' |
17.9 NextResponse 的常用方法
// 返回 JSON
return NextResponse.json({ data: 'hello' })
// 返回 JSON 并设置状态码
return NextResponse.json({ error: '未找到' }, { status: 404 })
// 重定向
return NextResponse.redirect(new URL('/login', request.url))
// 设置响应头
const response = NextResponse.json({ data: 'hello' })
response.headers.set('X-Custom-Header', 'my-value')
return response
// 设置 Cookie
const response = NextResponse.json({ success: true })
response.cookies.set('token', 'abc123', { httpOnly: true })
return response
17.10 获取 URL 参数
查询参数(?key=value)
// 访问:/api/articles?page=2&limit=10
export async function GET(request) {
const page = request.nextUrl.searchParams.get('page') // '2'
const limit = request.nextUrl.searchParams.get('limit') // '10'
return NextResponse.json({ page, limit })
}
动态路由参数(放在文件夹名里)
src/app/api/articles/[id]/route.js → /api/articles/123
// src/app/api/articles/[id]/route.js
export async function GET(request, { params }) {
const { id } = await params // 注意:params 是异步的,需要 await
return NextResponse.json({ articleId: id })
}
⚠️ 在 Next.js 15+ 中,
params 是一个 Promise,必须用 await 获取。17.11 接口设计
| 接口 | 方法 | 说明 | 请求体 |
|---|---|---|---|
/api/comments | GET | 获取文章的所有评论 | 无 |
/api/comments | POST | 提交新评论 | { user, content, articleId } |
17.12 完整代码
📄 查看完整 comments/route.js 代码
// src/app/api/comments/route.js
import { NextResponse } from 'next/server'
// 模拟数据库
let comments = [
{ id: 1, articleId: 'hello-world', user: '小明', content: '写得不错!', time: '2026-06-10' },
{ id: 2, articleId: 'hello-world', user: '小红', content: '学到了!', time: '2026-06-11' },
{ id: 3, articleId: 'react-basics', user: '小刚', content: '感谢分享', time: '2026-06-11' }
]
// GET:获取评论(支持按文章筛选)
export async function GET(request) {
const articleId = request.nextUrl.searchParams.get('articleId')
let result = comments
if (articleId) {
result = comments.filter(c => c.articleId === articleId)
}
return NextResponse.json({
success: true,
total: result.length,
data: result
})
}
// POST:添加评论
export async function POST(request) {
try {
const body = await request.json()
// 验证必填字段
if (!body.user || !body.content || !body.articleId) {
return NextResponse.json(
{ success: false, message: '缺少必填字段:user、content、articleId' },
{ status: 400 }
)
}
// 验证内容长度
if (body.content.length > 500) {
return NextResponse.json(
{ success: false, message: '评论内容不能超过 500 字' },
{ status: 400 }
)
}
// 创建新评论
const newComment = {
id: comments.length + 1,
articleId: body.articleId,
user: body.user,
content: body.content,
time: new Date().toISOString().split('T')[0]
}
comments.push(newComment)
return NextResponse.json({
success: true,
data: newComment,
message: '评论成功!'
}, { status: 201 })
} catch (error) {
return NextResponse.json(
{ success: false, message: '请求格式错误,请发送 JSON' },
{ status: 400 }
)
}
}
17.13 前端调用
在文章页面中调用 POST 接口提交评论:
📄 查看前端调用代码 (page.js)
// src/app/articles/[slug]/page.js(部分代码)
'use client'
import { useState } from 'react'
export default function ArticlePage() {
const [comments, setComments] = useState([])
const [user, setUser] = useState('')
const [content, setContent] = useState('')
// 提交评论
async function handleSubmit(e) {
e.preventDefault()
// 发送 POST 请求
const res = await fetch('/api/comments', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
user: user,
content: content,
articleId: 'hello-world'
})
})
const data = await res.json()
if (data.success) {
setComments([...comments, data.data])
setContent('')
alert('评论成功!')
} else {
alert('评论失败:' + data.message)
}
}
return (
<div>
<h1>文章页面</h1>
{/* 评论表单 */}
<form onSubmit={handleSubmit}>
<input
value={user}
onChange={(e) => setUser(e.target.value)}
placeholder="你的名字"
required
/>
<textarea
value={content}
onChange={(e) => setContent(e.target.value)}
placeholder="写下你的评论..."
required
/>
<button type="submit">提交评论</button>
</form>
{/* 评论列表 */}
<div>
{comments.map(c => (
<div key={c.id}>
<strong>{c.user}</strong> · {c.time}
<p>{c.content}</p>
</div>
))}
</div>
</div>
)
}
调用流程
用户点击"提交评论"
↓
前端 fetch('/api/comments', { method: 'POST', body: ... })
↓
Next.js 找到 app/api/comments/route.js 的 POST 函数
↓
执行 POST 函数,解析请求体,创建评论
↓
返回 JSON { success: true, data: {...} }
↓
前端收到响应,更新页面显示
💡 这就是前后端一体开发的魅力——不需要跨域、不需要单独部署后端,前端直接调用自己项目的接口。
本章复盘——API Routes 核心要点
| 要点 | 说明 |
|---|---|
| API Routes | pages/api 目录下创建后端接口 |
| 请求处理 | req.method 区分 GET/POST,req.body 获取数据 |
| 动态路由 | [slug].js 处理动态参数 |
| 数据验证 | 服务端校验输入,防止恶意请求 |
下一章预告(第18章):我们将学习样式与资源处理——CSS Modules、图片优化和字体加载。
本文档由 zyyc-0336 编写,最后更新:2026-06-14