用php原生实现restful接口需四步:1. 用$_server['request_method']区分http方法;2. 用file_get_contents('php://input')+json_decode解析json请求体;3. 用正则从request_uri提取路径参数并强校验;4. 按规范返回对应状态码与统一json结构(status/data/message)。

怎么用 PHP 原生写一个能跑通的 RESTful 接口
不用框架也能做,关键是把 HTTP 方法、状态码、请求体解析和路由分发这四件事对上。PHP 自带 $_SERVER['REQUEST_METHOD'] 和 file_get_contents('php://input') 就够用了,别一上来就装 Laravel 或 Slim。
常见错误是直接用 $_POST 接 JSON 请求——它只处理 application/x-www-form-urlencoded 和 multipart/form-data,而 REST 大多走 application/json。
- 用
getallheaders()或$_SERVER读取Content-Type,判断是否为application/json - 是的话,用
json_decode(file_get_contents('php://input'), true)解析请求体,不是$_POST - 手动根据
$_SERVER['REQUEST_URI']做简单路由,比如匹配/api/users或/api/users/123 - 每个分支里,用
http_response_code(200)、http_response_code(404)显式设状态码,别依赖默认 200
为什么 GET / POST / PUT / DELETE 要严格对应资源操作
不是为了“规范好看”,而是客户端(尤其是前端框架或移动端 SDK)会按这个约定自动处理缓存、重试、幂等性。比如 Vue 的 axios.put() 默认发 PUT,你后端却用 POST 接,就容易丢数据或重复提交。
典型错法:用 POST /api/users 创建用户没问题,但用 POST /api/users/123 更新用户——这违反 REST 约定,也导致无法被标准工具识别为更新操作。
立即学习“PHP免费学习笔记(深入)”;
-
GET /api/users→ 列表,可缓存,无副作用 -
POST /api/users→ 创建新资源,返回201 Created+Location头 -
GET /api/users/123→ 单条,支持条件查询(如?include=profile) -
PUT /api/users/123→ 全量替换,客户端必须传完整字段;PATCH才是局部更新(需额外判断是否支持) -
DELETE /api/users/123→ 删除,应返回204 No Content,不是200 OK+ 空 JSON
如何安全地解析 URL 路径参数和查询参数
PHP 的 parse_url() 和 $_GET 不足以应对 REST 场景,尤其路径里带 ID 时,容易被注入或越权。比如 /api/posts/5;admin=1 这种恶意路径,直接拼进 SQL 就炸了。
关键不是“怎么取值”,而是“怎么验证值”。别信任何来自请求的原始字符串。
- 用正则从
$_SERVER['REQUEST_URI']提取 ID:preg_match('@^/api/users/(\d+)$@', $uri, $matches),强制要求是数字 - 查询参数如
?page=2&limit=10,用filter_input(INPUT_GET, 'page', FILTER_VALIDATE_INT, ['options' => ['default' => 1, 'min_range' => 1]])做强校验 - 永远不要把未过滤的
$id直接拼进 SQL,哪怕只是"SELECT * FROM users WHERE id = $id" - 如果用 PDO,参数化是底线;如果用原生 MySQLi,至少过一遍
mysqli_real_escape_string()(仅限字符串字段)
响应格式不统一,前端就天天报错
前端最烦的不是接口挂了,而是同一个接口有时返回 {"data":{...}},有时返回 {"error":"xxx"},有时又直接裸对象。这不是风格问题,是契约断裂。
定好结构,然后死守。建议用三段式:status(布尔)、data(成功时主体)、message(失败时提示)。别加多余字段,别动态删 key。
- 成功响应示例:
{"status":true,"data":{"id":123,"name":"Alice"}} - 失败响应示例:
{"status":false,"message":"User not found","data":null} - 所有响应统一设
header('Content-Type: application/json; charset=utf-8'),避免中文乱码 - 别在失败时返回
200 OK+ 错误 message——HTTP 状态码才是机器可读的“第一信号”
真正难的不是写完一个接口,而是让所有接口在状态码、参数校验、错误结构、ID 安全提取上保持一致。这些细节没人盯着看,但只要漏掉一处,前端联调时就会卡半天,还查不出哪的问题。











