2.3 Web 开发相关:响应报文的装配车间


文档摘要

2.3 Web 开发相关:响应报文的装配车间 本节摘要:请求处理完,出站的列车由三节车厢组成:状态码、响应头、正文。本节讲状态码的选择逻辑、常用响应头的装配方法、JSON 输出的正确姿势与重定向、下载、跨域三个高频场景,最后把前两节的数据库能力串成一个能被前端调用的 JSON 接口。2.2 负责"算出结果",本节负责"把结果漂亮地递出去"。 响应不只是正文 新手常以为"响应就是 echo 出来的内容",其实正文只是最后一节车厢。浏览器或前端程序先看状态码(这次出车成功还是失败、是什么性质的失败),再读响应头(正文是什么类型、要不要缓存、跳去哪里),最后才消费正文。装配顺序也有讲究:状态码与响应头必须在任何正文输出之前发车,PHP 一旦开始输出正文,头部就再改不了——这与 1.

2.3 Web 开发相关:响应报文的装配车间

本节摘要:请求处理完,出站的列车由三节车厢组成:状态码、响应头、正文。本节讲状态码的选择逻辑、常用响应头的装配方法、JSON 输出的正确姿势与重定向、下载、跨域三个高频场景,最后把前两节的数据库能力串成一个能被前端调用的 JSON 接口。2.2 负责"算出结果",本节负责"把结果漂亮地递出去"。

响应不只是正文

新手常以为"响应就是 echo 出来的内容",其实正文只是最后一节车厢。浏览器或前端程序先看状态码(这次出车成功还是失败、是什么性质的失败),再读响应头(正文是什么类型、要不要缓存、跳去哪里),最后才消费正文。装配顺序也有讲究:状态码与响应头必须在任何正文输出之前发车,PHP 一旦开始输出正文,头部就再改不了——这与 1.8 节 Cookie 的时序要求是同一条规矩。

状态码的选择逻辑用一张速查表就够:

场景 状态码 一句话理由
查询成功返回数据 200 标准成功
新建资源成功 201 告知"已建档",可附新资源地址
表单校验失败 422 请求格式对,但内容不合格
未登录访问受限页 401 身份未认证,请先登录
已登录但权限不足 403 认证通过,岗位不够
资源不存在 404 站台编号查无此项
方法不允许 405 用 GET 访问了只收 POST 的窗口
服务器内部故障 500 月台自己的问题,勿让旅客背锅

判断口径只有一条:4 开头是旅客的问题,5 开头是站方的问题。把业务失败塞进 500 让前端没法精准提示,把站方故障谎报成 404 掩盖了真实问题——两类错位都会在排查时加倍偿还。

常用响应头:装哪几件、怎么装

<?php // JSON 接口的标准开头三件套 http_response_code(200); header('Content-Type: application/json; charset=utf-8'); // 缓存控制:动态数据一般不让中间环节私存 header('Cache-Control: no-store'); // 重定向:告诉旅客去别的站台 header('Location: /new-hall.php', true, 302); exit; // 重定向后立即收班,防止继续执行

三个易错点。其一,charset=utf8mb4utf-8 要写进类型头,否则中文按默认编码解读,1.5 节的三端一致在出站端失守。其二,Location 配的状态码有讲究:临时跳转用 302 或 307,资源永久搬家用 301,语义错了搜索引擎会记错账。其三,header 前不能有任何输出——哪怕一个空格,都会触发"头部已发送"告警,正文意外提前发车。

JSON 输出:接口时代的标准正文

现代前后端分离架构下,服务端最常见的正文是 JSON。输出的固定姿势:

<?php function jsonResponse(array $data, int $status = 200): never { http_response_code($status); header('Content-Type: application/json; charset=utf-8'); echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); exit; } jsonResponse(['code' => 0, 'msg' => '受理成功', 'data' => ['id' => 15]]); // {"code":0,"msg":"受理成功","data":{"id":15}}

JSON_UNESCAPED_UNICODE 让中文直接输出而不是转义成一串反斜杠数字,可读性与传输体积双赢。返回值要留意 falsejson_encode 遇到无法编码的数据(如非法 UTF-8 序列)会失败返回 false,接口一旦把 false 当正文发出去,前端拿到的就是四个字母的"尸体"。稳妥写法是检查返回值或提前保证数据干净。

跨域:别的站台的列车要借道

前端域名与接口域名不同时(例如页面在 www 域、接口在 api 域),浏览器按同源策略拦截响应,除非站方在响应头里明确放行。最小放行集合:

<?php header('Access-Control-Allow-Origin: https://前端站点域名'); // 指定来源,勿用星号配凭证 header('Access-Control-Allow-Methods: GET, POST, OPTIONS'); header('Access-Control-Allow-Headers: Content-Type, X-Token'); if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(204); // 预检请求直接放行,无正文 exit; }

浏览器对"带自定义头的复杂请求"会先发一次 OPTIONS 预检,服务端要在处理业务前把预检接住。生产环境建议把来源收敛成白名单数组校验,而不是无差别放行。

实战:把班次查询做成 JSON 接口

综合 2.2 的 PDO 与本节的装配能力,写一个前端可调的查询接口:

<?php // api/trips.php?from=南苑&to=虹桥 —— GET 查询接口 declare(strict_types=1); $from = trim((string) ($_GET['from'] ?? '')); $to = trim((string) ($_GET['to'] ?? '')); if ($from === '' || $to === '') { http_response_code(422); header('Content-Type: application/json; charset=utf-8'); echo json_encode(['code' => 422, 'msg' => '出发与到达站均必填'], JSON_UNESCAPED_UNICODE); exit; } $pdo = new PDO('mysql:host=127.0.0.1;dbname=station;charset=utf8mb4', 'station_user', '强口令', [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, ]); $stmt = $pdo->prepare('SELECT trip, depart, arrive, fare FROM trips WHERE station_from = ? AND station_to = ? ORDER BY depart'); $stmt->execute([$from, $to]); http_response_code(200); header('Content-Type: application/json; charset=utf-8'); echo json_encode(['code' => 0, 'data' => $stmt->fetchAll()], JSON_UNESCAPED_UNICODE);

验证方式:浏览器直接访问带参数的地址(GET 天然可测),或命令行 curl "地址?from=南苑&to=虹桥",观察返回的 JSON。操作链条值得复述:参数校验失败给 422 加原因,查询成功给 200 加数据数组,全程预处理。这个接口在第 3.2 节会被框架路由接管,到时对比着看,框架替你干了哪些活会非常具体。

常见坑

⚠️ 头部输出后再改状态码:报"头部已发送",输出正文前的所有头部动作集中放脚本开头。

⚠️ 接口报错仍返回 200:前端拿到 200 就按成功解析,错误被藏进正文,监控与告警全部失灵——状态码要诚实。

本节要点回顾

  • 三节车厢:状态码、响应头、正文按序装配,头部动作永远在正文之前。
  • 4 与 5 的分界:4 开头旅客的问题,5 开头站方的问题,状态码是给排查人看的真话。
  • JSON 三要素:类型头带字符集、JSON_UNESCAPED_UNICODE、检查编码失败。
  • 跨域最小集:来源白名单、方法与头部声明、OPTIONS 预检先行放行。
  • 接口骨架:校验给 422、成功给 200、查询走预处理——与本册前文严丝合缝。

下一节补几件趁手的高级武器:闭包进阶、生成器与反射,它们让 PHP 在特定场景下干出"不像 PHP"的活。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U