ThinkPHP控制器需用file_get_contents('php://input')读取JSON等非表单POST数据,因$request->post()仅支持application/x-www-form-urlencoded和multipart/form-data;Swoole环境推荐$request->getContent()。
ThinkPHP控制器接收原始POST数据,不能只依赖
或
—— 这些方法只解析
和
类型的数据,对 JSON、XML、纯文本或自定义二进制 payload 会直接返回空数组。
为什么
拿不到 JSON 数据
ThinkPHP 的
内部调用的是 PHP 的
超全局变量,而
只在请求头为
或
时由 PHP 自动解析填充。当前端发来
时,PHP 不解析,
为空,框架自然也读不到。
现象:前端用
,后端
返回
验证方式:打印
,确认是否为
或其他非表单类型
正确做法:跳过框架解析层,直接读取原始输入流
用
读原始数据
这是最通用、兼容性最好的方式,适用于 JSON、XML、YAML、Protobuf 等任意非表单格式的 POST 数据(但不支持
)。
是只读流,只能读一次;若你已在框架中触发过
或
,可能已被消耗,需在控制器方法开头立即读取
示例代码:
注意:
在
场景下不可用,此时应改用
+
组合处理
不同 Content-Type 下该选哪种方式
别硬套一种写法,必须根据请求头动态适配:
PHP 8.5.5
PHP 8.5.5 是 PHP 8.5 分支的维护更新版本。该版本延续了“小步快跑”的迭代逻辑,通过深度错误修复、底层性能微调以及安全加固,旨在为开发者提供一个更健壮、更高效的运行环境。该版本严格遵守语义化版本规范,不包含破坏性变更。
下载
立即学习
“
PHP免费学习笔记(深入)
”;
→ 用
或
,安全且带自动过滤
→ 必须用
+
,别试图用
强转
或
→ 同样走
,再用
解析
(如上传二进制文件)→
直接保存,或配合
流式写入
混合场景(比如同时传 JSON body + query 参数)→
拿 query,
拿 body,不要混用
容易被忽略的坑:Swoole / Swoft / RoadRunner 环境下
失效
在常驻内存的协程服务器(如 Swoole)中,
可能被提前读取或不可用,尤其在启用
或中间件已消费流时。
解决方案:优先使用
(ThinkPHP 6+ 支持),它封装了对不同 SAPI 的兼容读取逻辑
TP6 示例:
,比手写
更可靠
若用 TP5.1,可加一层 fallback:
,但后者需
php
.ini 开启
(已废弃,不推荐)
调试建议:在控制器开头加
对比三者输出
$this->request->post()input('post.')Content-Type: application/x-www-form-urlencodedmultipart/form-data$this->request->post()Request::post()$_POST$_POSTapplication/x-www-form-urlencodedmultipart/form-dataContent-Type: application/json$_POSTfetch({ method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({a:1}) })$this->request->post()[]$this->request->header('content-type')application/jsonfile_get_contents('php://input')multipart/form-dataphp://input$this->request->param()$this->request->post()$raw = file_get_contents('php://input');
if (empty($raw)) {
throw new \think\Exception('Empty raw POST data');
}
$data = json_decode($raw, true);
if (json_last_error() !== JSON_ERROR_NONE) {
throw new \think\Exception('Invalid JSON format');
}php://inputenctype="multipart/form-data"$_FILES$_POSTapplication/x-www-form-urlencoded$this->request->post('key')input('post.key')application/jsonfile_get_contents('php://input')json_decode()$this->request->param()text/xmlapplication/soap+xmlphp://inputsimplexml_load_string()application/octet-streamphp://inputstream_copy_to_stream()$this->request->get()php://inputphp://inputphp://inputenable_static_handler$this->request->getContent()$raw = $this->request->getContent();php://inputfile_get_contents('php://input') ?: ($GLOBALS['HTTP_RAW_POST_DATA'] ?? '')always_populate_raw_post_datavar_dump($GLOBALS['HTTP_RAW_POST_DATA'], file_get_contents('php://input'), $this->request->getContent());