PHP 8.0 原生实现 RESTful API 必须手动处理路由分发、请求体解析、JSON 响应封装和 HTTP 状态码设置;需用 $_SERVER['REQUEST_METHOD'] 和 parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH) 可靠提取路径,php://input 读取 JSON 数据并校验,统一设 Content-Type: application/json; charset=utf-8 头,用 http_response_code() 设置状态码,PDO 操作须异常捕获并隐藏敏感信息。

PHP 8.0 实现 RESTful API 不需要框架也能跑通,但必须手动处理好四件事:路由分发、请求体解析、JSON 响应封装、HTTP 状态码设置。漏掉任意一环,前端就可能收不到数据、解析失败或误判状态。
怎么用 $_SERVER['REQUEST_METHOD'] 和 parse_url() 做基础路由
原生 PHP 没有自动路由,得靠自己拆 URL 并匹配动词。别直接用 $_SERVER['PATH_INFO']——它在某些 Nginx 配置下为空,parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH) 更可靠。
- 提取路径后要
trim()开头结尾斜杠,避免/api/users/和/api/users被当成两个路由 - 用
explode('/', $path)拆出段,第 3 段(索引 2)通常是资源 ID,但要检查是否为数字,否则可能被注入恶意路径 - 未匹配的路径或方法必须返回
405 Method Not Allowed或404 Not Found,不能静默失败 - 示例判断逻辑:
$method = $_SERVER['REQUEST_METHOD']; $path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH); $path = trim($path, '/'); $parts = explode('/', $path); if ($parts[0] === 'api' && $parts[1] === 'users') { if ($method === 'GET' && !isset($parts[2])) { getUsers(); } elseif ($method === 'POST') { createUser(); } elseif ($method === 'GET' && isset($parts[2]) && is_numeric($parts[2])) { getUser((int)$parts[2]); } }
为什么 php://input 比 $_POST 更适合接收 JSON 数据
前端发 Content-Type: application/json 时,$_POST 是空的——PHP 只自动解析 application/x-www-form-urlencoded 和 multipart/form-data。必须读原始输入流。
- 用
file_get_contents('php://input')获取原始 JSON 字符串,再用json_decode($raw, true)转数组 - 必须检查
json_last_error(),常见错误如JSON_ERROR_SYNTAX(前端多逗号)或JSON_ERROR_DEPTH(嵌套太深),此时应返回400 Bad Request - 空请求体(如 DELETE)也要容错,
php://input返回空字符串,json_decode('')会返回null,需提前判断 - 别忘了过滤:即使用了
json_decode,字段值仍可能是恶意字符串,后续数据库写入前必须过filter_var()或 PDO 参数绑定
header('Content-Type: application/json; charset=utf-8') 必须在任何输出前调用
一旦有空格、BOM 或 echo 输出,header 就会失效,前端收到的是 HTML 错误页而非 JSON。这是调试时最常踩的坑。
立即学习“PHP免费学习笔记(深入)”;
- 所有响应前加
header('Content-Type: application/json; charset=utf-8'),且确保前面没print、var_dump或文件末尾多余换行 - 中文不乱码的关键是
json_encode($data, JSON_UNESCAPED_UNICODE),否则默认转成 \uXXXX - 空结果必须显式输出
[]或{},不能echo json_encode(null)(前端解析为null,易引发 JS 错误) - 状态码要用
http_response_code(201)或header('HTTP/1.1 201 Created'),仅设 header 不改变实际状态码
PDO 预处理和异常处理怎么避免暴露敏感信息
数据库报错直接打屏会泄露表名、字段甚至服务器路径。PHP 8.0 的 PDO::ERRMODE_EXCEPTION 是双刃剑:方便捕获,但也危险。
- 连接时必须设
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,否则prepare()失败静默返回false - 所有数据库操作包在
try/catch (PDOException $e)里,catch中只记录日志(error_log($e->getMessage())),绝不echo $e->getMessage() - 对用户返回的错误信息要重写,比如 “用户不存在” 而不是 “SQLSTATE[42S22]: Column not found: 1054 Unknown column 'xxx' in 'where clause'”
- 查询无结果时,不要抛异常,应返回空数组并设
http_response_code(404);只有连接失败、语法错误等才算真正异常
真正的难点不在写通,而在边界情况:ID 传了字符串怎么转整型、PUT 请求没带 body 怎么处理、并发更新时的脏读、JWT 过期后该返回 401 还是 403……这些不会出现在“Hello World”例子里,但上线第一天就会撞上。



















