Next.js 从入门到精通(2):路由处理器(Route Handlers):用标准 Request/Response 写后端接口

5 阅读7分钟

大家好,我是jobleap.cn的小九。

对于后端开发者而言,本章内容会格外熟悉——我们将回归核心的后端开发场景:HTTP 请求、状态码与 JSON 数据交互。Next.js 不仅是 React 渲染框架,更是功能完备的后端框架,支持像 FastAPI 一样编写标准 REST API,无需额外学习框架专属语法,且兼容 Cloudflare Workers、Deno 等平台的标准 Web API。

1. 核心映射:FastAPI 开发者快速上手 Route Handlers

FastAPI 中通过装饰器绑定路由与逻辑,而 Next.js App Router 的核心规则是 “文件位置决定 API 路径”,两者的核心概念可以直接对应,降低迁移成本:

概念FastAPI 实现方式Next.js Route Handler 实现方式
文件定义main.py / routers/*.pyapp/api/.../route.ts
请求方法绑定@app.get / @app.post 装饰器export async function GET / POST
获取 URL 参数def read_item(q: str):request.nextUrl.searchParams.get('q')
读取请求体item: Item(Pydantic 模型)await request.json()
返回 JSON 数据return {"msg": "hi"}return NextResponse.json({ msg: "hi" })

关键规则(必看)

  • Route Handler 必须定义在名为 route.ts 的文件中;
  • route.ts 不能与 page.tsx 放在同一文件夹(会导致 URL 路径冲突);
  • 推荐将所有 API 文件放在 src/app/api/ 目录下,便于统一管理。

2. 实战:构建帖子 API(GET/POST 基础接口)

我们以社区系统的核心接口为例,实现“获取帖子列表”和“发布新帖子”功能,全程还原标准 REST API 开发流程。

第一步:创建目录结构

首先在 src/app/api/ 下创建 posts 文件夹,再在该文件夹下新建 route.ts(对应 API 路径 /api/posts)。

2.1 编写 GET 接口(查询数据)

实现 GET /api/posts 接口,返回帖子列表,模拟数据库查询逻辑:

// src/app/api/posts/route.ts
import { NextResponse } from "next/server";

// 模拟数据库数据(实际项目中替换为真实数据库查询)
const posts = [
  { id: 1, title: "Next.js 16 发布了", content: "PPR 功能太强了..." },
  { id: 2, title: "FastAPI 转 Next.js 心得", content: "路由系统很不一样..." },
];

// 导出 GET 函数,对应 HTTP GET 请求
export async function GET() {
  // 模拟数据库查询延迟(实际项目可删除)
  // await new Promise(resolve => setTimeout(resolve, 1000));

  // 直接返回 JSON 数据,Next.js 自动处理 Content-Type: application/json 响应头
  return NextResponse.json({
    code: 0,
    data: posts,
    message: "获取成功"
  });
}

启动项目后,访问 http://localhost:3000/api/posts 即可看到 JSON 响应,与 FastAPI 的返回格式完全一致。

2.2 编写 POST 接口(提交数据)

在同一 route.ts 文件中,导出 POST 函数即可实现“发布新帖子”接口,支持请求体解析、参数验证和错误处理:

// src/app/api/posts/route.ts(补充 POST 方法)
import { NextRequest, NextResponse } from "next/server";

// 导出 POST 函数,对应 HTTP POST 请求
export async function POST(request: NextRequest) {
  try {
    // 1. 解析请求体(类似 FastAPI 的 Pydantic 模型接收数据)
    const body = await request.json();
    
    // 2. 基础参数验证(第 12 章将引入 Zod 实现强类型验证)
    if (!body.title || !body.content) {
      return NextResponse.json(
        { error: "标题和内容不能为空" },
        { status: 400 } // 400 Bad Request 状态码
      );
    }

    // 3. 模拟存入数据库(实际项目中替换为数据库插入操作)
    const newPost = {
      id: Date.now(), // 用时间戳作为临时 ID
      title: body.title,
      content: body.content,
      createdAt: new Date().toISOString(), // 格式化创建时间
    };

    // 4. 返回 201 Created 状态码(表示资源创建成功)
    return NextResponse.json(
      { code: 0, data: newPost, message: "发布成功" },
      { status: 201 }
    );

  } catch (error) {
    // 捕获 JSON 解析失败等异常
    return NextResponse.json(
      { error: "无效的 JSON 数据" },
      { status: 500 } // 500 Internal Server Error 状态码
    );
  }
}

测试方式:使用 Postman、curl 或前端表单提交 POST 请求到 http://localhost:3000/api/posts,请求体携带 titlecontent 字段即可完成测试,完全遵循 REST API 规范。

3. 动态路由:实现帖子修改/删除(PATCH/DELETE)

类似 FastAPI 的 /items/{item_id} 路径参数,Next.js 用 [id] 命名的文件夹捕获动态参数,实现“修改单个帖子”“删除单个帖子”接口。

第一步:创建动态路由目录

src/app/api/posts/ 下创建 [id] 文件夹(方括号表示动态参数),再在该文件夹下新建 route.ts(对应 API 路径 /api/posts/{id})。

第二步:编写 PATCH/DELETE 接口

通过函数参数 params 获取动态路由中的 id,实现针对性的更新和删除逻辑:

// src/app/api/posts/[id]/route.ts
import { NextRequest, NextResponse } from "next/server";

// 处理 HTTP DELETE 请求(删除帖子)
export async function DELETE(
  request: NextRequest,
  { params }: { params: { id: string } } // 接收动态路由参数 id
) {
  const postId = params.id; // 获取帖子 ID

  // 实际项目中执行数据库删除逻辑(此处仅打印日志模拟)
  console.log(`删除帖子 ID: ${postId}`);

  return NextResponse.json({
    message: `帖子 ${postId} 已删除`
  });
}

// 处理 HTTP PATCH 请求(更新帖子)
export async function PATCH(
  request: NextRequest,
  { params }: { params: { id: string } }
) {
  const postId = params.id;
  const updateData = await request.json(); // 解析更新数据

  // 实际项目中执行数据库更新逻辑(此处仅返回参数模拟)
  return NextResponse.json({
    message: `帖子 ${postId} 更新成功`,
    updatedData: updateData
  });
}

版本注意事项

Next.js 15/16 中,params 可能会变为 Promise 类型(取决于项目配置),若遇到参数获取失败,可尝试用 const { id } = await params 解析(标准 Route Handlers 场景下仍为对象形式)。

4. 避坑指南:缓存机制(Python 开发者重点关注)

FastAPI 默认是动态模式——每次请求都会重新执行函数逻辑;而 Next.js 为优化性能,默认优先静态化处理,这是 Python 开发者最容易踩坑的点:

静态化的“陷阱”

如果 GET 接口满足以下条件,Next.js 会在构建(Build)时执行一次函数并生成静态 JSON 文件,后续所有请求都会直接返回该静态文件(数据不会实时更新):

  • 没有使用 request 对象(如未读取 URL 参数、请求头);
  • 没有使用 Cookies、Headers 等动态数据;
  • 没有显式声明动态模式。

强制动态模式(解决数据不更新问题)

若需要接口像 FastAPI 一样“每次请求都重新执行逻辑”(如实时查询数据库),只需在 route.ts 中添加配置:

// src/app/api/posts/route.ts(添加动态模式配置)
export const dynamic = 'force-dynamic'; // 强制每次请求都重新执行

export async function GET() {
  // 数据库查询等实时逻辑(现在会每次请求都执行)
}

自动动态模式

无需手动配置 dynamic: 'force-dynamic' 的场景:

  • 接口中使用了 request.nextUrl.searchParams(读取 URL 参数);
  • 接口中使用了 cookies()headers() 等动态方法;
  • 接口是 POST/PATCH/DELETE 等非 GET 方法(默认动态)。

5. 前端组件中调用 API(客户端组件场景)

虽然 Next.js 支持在 Server Component 中直接查询数据库,但这里我们模拟“前端请求后端 API”的经典场景(需使用客户端组件),在 src/app/posts/page.tsx 中调用上述接口:

// src/app/posts/page.tsx
"use client"; // 标记为客户端组件(才能使用 useEffect、fetch 等浏览器 API)

import { useEffect, useState } from "react";

// 定义数据类型(类似 FastAPI 的 Pydantic Model,约束数据结构)
interface Post {
  id: number;
  title: string;
  content: string;
}

export default function PostsPage() {
  const [posts, setPosts] = useState<Post[]>([]);
  const [loading, setLoading] = useState(true);

  // 组件挂载后调用 API
  useEffect(() => {
    fetch("/api/posts") // 调用我们编写的 GET 接口
      .then((res) => res.json())
      .then((data) => {
        setPosts(data.data); // 存储返回的帖子列表
        setLoading(false); // 关闭加载状态
      });
  }, []);

  if (loading) return <div>加载中...</div>;

  return (
    <div className="p-10">
      <h2 className="text-2xl font-bold mb-4">API 数据流展示</h2>
      <div className="space-y-4">
        {posts.map((post) => (
          <div key={post.id} className="border p-4 rounded shadow bg-white">
            <h3 className="font-bold text-lg">{post.title}</h3>
            <p className="text-gray-600">{post.content}</p>
          </div>
        ))}
      </div>
    </div>
  );
}

启动项目后访问 /posts 页面,即可看到从 API 接口获取并渲染的帖子列表,完整实现“前端请求 → 后端处理 → 数据返回 → 页面渲染”的全流程。

本章核心总结

  1. 标准兼容性:Route Handlers 基于标准 Web Request/Response API 构建,无框架专属语法,学到的知识可复用在 Cloudflare Workers、Deno 等平台;
  2. 路由规则app/api/xxx/route.ts 对应 /api/xxx 接口,文件路径即 API 路径,避免路径冲突;
  3. 请求处理:通过导出 GET/POST/PATCH/DELETE 异步函数绑定 HTTP 方法,请求体、参数、响应的处理逻辑与 FastAPI 一致;
  4. 缓存避坑:默认静态化可能导致数据不更新,实时场景需显式声明 dynamic: 'force-dynamic',或使用 URL 参数、Cookies 触发自动动态;
  5. 前后端联动:客户端组件中通过 fetch 调用 API,数据类型定义可对应 FastAPI 的 Pydantic 模型,保持类型一致性。

下一步预告

有了基础的接口和数据流转,接下来需要让内容更易被搜索引擎发现——Python 后端通常将 SEO 交给前端,但 Next.js 允许开发者直接掌控 SEO 配置。下一章《Next.js 从入门到精通(3):SEO 与元数据 API:动态生成 Title 与 Open Graph 配置》,将教你如何让页面在 Google 搜索和社交平台分享中获得更好的展示效果。