写出第一个后端接口
第一个后端接口先做一件小事:接收请求、运行处理、返回可检查的 JSON。每个阶段都要留下日志或响应证据。
- 任务列表接口可以启动和访问,正常路径返回 JSON,未知路径返回明确状态。
- 路由、处理函数、参数和响应模型
- 复现写出第一个后端接口后,应当任务列表接口可以启动和访问,正常路径返回 JSON,未知路径返回明确状态,并保留状态码、响应结构、进程输出和前后端同一次请求作为可重复检查的依据。
- 完成 5.2「后端运行环境与依赖隔离」
FOUNDATION
必须理解
后端在可信环境接收请求、验证输入、执行规则并返回响应。第一个接口的重点不是框架语法,而是看清路由、处理函数和响应之间的关系。
本课依次讲清路由、处理函数、参数和响应模型、前端代码与服务端代码的信任边界和开发服务器、端口和接口调试,最后通过“分别发送正常、空标题和错误 JSON 请求,记录状态码”检查学习结果。
前端是柜台,后端处理函数是办事窗口。窗口先确认你要办什么、材料是否齐全,再按规则处理并给回执;不能因为柜台说“合法”就跳过检查。
在 Next.js App Router 中创建 /api/tasks Route Handler,GET 返回示例任务,POST 读取 JSON 标题并返回新任务。
路由、处理函数、参数和响应模型
路由会把某个 URL 和方法交给对应的处理函数。Next.js 的 Route Handler 放在 app/api/.../route.ts,同一个地址可以分别处理 GET 和 POST。
基础概念
路由把 HTTP 方法与 URL 匹配到处理函数;参数把请求中的路径、查询或正文数据交给函数;响应模型规定返回状态、头部和正文的结构。
进一步理解
同一个 `/api/tasks` 可以用 GET 读取、POST 创建。框架完成匹配和基础解析,处理函数仍要校验输入、执行规则并选择正确响应。
路径参数常标识资源,查询参数常描述筛选,正文承载复杂提交。来源不同不代表可信度不同,全部外部输入都要验证。
POST `/api/tasks` 进入创建函数,读取 JSON 标题,校验后生成任务,返回 201 和任务对象。
路由文件不是数据库表,响应模型也不是内部实体;入口契约应与存储实现保持可控距离。
这一小节记住:一个后端端点就是明确入口、可信处理和结构化响应。
前端代码与服务端代码的信任边界
请求里有方法、请求头和正文,响应里有状态码、响应头和正文。服务端可以读取秘密配置,但从浏览器传来的每一个值都得当成不可信输入。
基础概念
信任边界是数据从不受控制环境进入可信执行环境的位置。浏览器、URL、请求头和 JSON 都可被调用者修改,服务端必须重新验证身份、权限和业务规则。
进一步理解
前端校验改善体验,可以提前提示空标题;攻击者或其他程序却能绕过页面直接发请求,因此不能把前端结果当安全依据。
服务端能访问数据库和秘密配置,返回响应时要只挑选允许公开字段。日志与错误也不能泄露堆栈、路径和凭证。
即使按钮只给管理员显示,POST 接口仍从服务端会话读取真实身份并检查角色,而不相信请求体中的 `role:'admin'`。
TypeScript 类型只在开发和编译阶段提供检查,网络传来的 JSON 在运行时仍可能是任意形状。
这一小节记住:凡是跨过网络进入服务端的数据,都先当成不可信输入。
开发服务器、端口和接口调试
TypeScript 能在写代码时提醒你类型不对,却管不到网络上确实发来的 JSON。别人完全可以绕过你的页面直接调用接口,所以运行时还要再校验。
基础概念
开发服务器是在本机监听端口、提供快速调试能力的进程。接口调试是用浏览器 Network、命令行或客户端工具检查请求和响应,而不仅看页面提示。
进一步理解
服务启动后会打印绑定地址与端口。连接失败先确认进程仍在运行、地址正确、端口未被占用;接口错误再看状态码、正文和服务端日志。
日志应带时间、请求标识和必要上下文,不能记录秘密。一次调试只改变一个变量,修改后重发同一请求比较结果。
用开发工具向 localhost 上的 POST 接口发送一个合法标题和一个空标题,对比 201 与 400,并在服务端日志找到两次请求。
浏览器能打开首页不代表 API 端口和路径正确;同一应用也可能有页面路由与接口路由两套处理。
这一小节记住:调试后端要同时观察客户端响应与服务端处理证据。
- 代码位于 Next.js App Router 的 `app/api/tasks/route.ts`。
- 示例只演示输入校验与响应,尚未写入数据库或检查用户身份。
export async function POST(request: Request) {
const body = await request.json();
if (typeof body.title !== "string" || !body.title.trim()) {
return Response.json({ error: "标题不能为空" }, { status: 400 });
}
return Response.json({ id: crypto.randomUUID(), title: body.title.trim(), done: false }, { status: 201 });
}阅读写出第一个后端接口示例时,即使 TypeScript 声明了类型,网络输入仍需在运行时检查。
- request.json 解析调用者提交的 JSON;解析本身也可能失败,生产实现需统一处理。
- 运行时检查 title 的类型和去空格结果,失败返回 400。
- 合法输入生成 id,并用 201 表示资源已创建。
合法标题得到 201 与任务 JSON;空字符串或非字符串得到 400;刷新页面不会保留该任务,因为示例没有数据库。
AI COLLABORATION
AI 如何参与
在写出第一个后端接口这一课,AI 负责根据真实材料解释路由、处理函数、参数和响应模型并指出遗漏,学习者负责控制范围、执行修改和核对状态码、响应结构、进程输出和前后端同一次请求。
推荐协作顺序
- 1
先让 AI 和你一起写 POST /api/tasks 的成功与失败响应。
- 2
契约确认后再生成 Route Handler,而且一次只实现一个方法。
- 3
不用前端,直接发送请求核对状态码和 JSON。
请根据当前后端框架和项目依赖生成一个最小只读任务接口。先列启动命令、路由和响应结构,再给代码。不要添加数据库、认证或额外框架。附 curl 与浏览器两种验证方式。
契约先于实现,GET/POST 职责分开,POST 对缺失标题返回明确 400,而不是永远 200;写出第一个后端接口的人工验收必须回到真实页面、请求、终端、测试或数据结果,不能用 AI 的文字说明代替。
人工检查清单
- 确认服务端没有相信客户端提供的 id、userId 或权限,错误响应结构一致。
- 让 AI 先写出方法、路径、输入、成功响应和失败响应,再生成处理函数。
- 绕过页面直接发送无效 JSON,确认服务端仍会拒绝并且响应不泄露内部信息。
COMMON TRAPS
常见误区
下面三类问题会让任务看似完成,却经不起刷新、错误输入或真实环境检查。先看现象,再找原因和修正方法。
一次加入所有后端功能
- 你会看到
- 启动错误与业务错误混在一起
- 为什么发生
- 启动、路由、校验和数据库同时变化,首个错误无法对应到单一环节。
- 怎样纠正
- 先走通单个只读接口
只看浏览器白屏
- 你会看到
- 没有检查状态码和响应正文
- 为什么发生
- 白屏是页面结果,服务端状态码和正文才说明请求是否到达以及为何失败。
- 怎样纠正
- 用 Network 或命令行查看完整响应
错误请求让进程退出
- 你会看到
- 一个坏输入使服务停止
- 为什么发生
- 用户输入属于可预期失败,不应沿未捕获异常终止整个服务进程。
- 怎样纠正
- 返回受控错误并保留服务运行
HANDS-ON
动手任务
任务列表接口可以启动和访问,正常路径返回 JSON,未知路径返回明确状态。
- 完成 5.2「后端运行环境与依赖隔离」
跟着做
- 01
写出 GET 与 POST 的请求响应契约。
- 02
创建 app/api/tasks/route.ts。
- 03
实现 GET 返回内存数组。
- 04
实现 POST 读取 JSON、校验标题并返回 201。
- 05
分别发送正常、空标题和错误 JSON 请求,记录状态码。
任务列表接口可以启动和访问,正常路径返回 JSON,未知路径返回明确状态。
为 GET 增加 ?done=true 查询条件,并说明过滤属于哪一层。
离开本课前,自问四件事
- 路由、处理函数、请求参数和响应模型怎样连接?
- 为什么前端已经校验后,后端仍必须再次校验?
- TypeScript 为什么不能保证网络 JSON 真实符合类型?
- 接口调试时应同时收集客户端与服务端哪些证据?
确认完成后,会同步更新学习中心的课程学习进度。