

统一声明:
1.本站联系方式QQ:709466365 TG:@UXWNET 官方TG频道:@UXW_NET 如果有其他人通过本站链接联系您导致被骗,本站一律不负责! 2.需要付费搭建请联系站长QQ:709466365 TG:@UXWNET 3.免实名域名注册购买- 游侠云域名 4.免实名国外服务器购买- 游侠网云服务
这篇文章把ThinkPHP中用Ajax接收JSON数据的正确方法拆得明明白白:从前端Ajax请求头的「关键配置」(比如必须加Content-Type: application/json
),到后端用input('json')
还是json_decode(file_get_contents('php://input'))
的区别,再到常见错误(比如POST/PUT请求的差异、跨域的快速解决)的排查技巧,甚至连如何用ThinkPHP日志快速定位问题都讲了。
不管你是刚入门的新手,还是踩过坑的老司机,跟着步骤走,5分钟就能解决这个烦人的bug——接下来的内容,看完就能直接复制用,比翻文档管用10倍!
你有没有过这种情况?前端用Ajax发了个JSON数据给ThinkPHP后端,控制台显示请求“成功200”,但后端var_dump($_POST)出来是空数组,或者拿到的是一串看不懂的字符串;要么就是报“数据格式不正确”,明明前端JSON.stringify()过了,后端还是解析不了——我去年帮做本地生活服务平台的朋友调过这个问题,他为了一个“提交用户收货地址”的接口,从下午3点调到晚上5点,最后发现就差一个前端请求头的配置。今天把我踩过的坑、摸透的逻辑全给你拆开讲,看完你十分钟就能搞定这个烦人的bug。
先搞懂:为什么你的Ajax传JSON总失败?
其实90%的问题都出在“前后端对‘数据格式’的理解不一致”——你以为前端发的是JSON,后端以为你发的是表单数据,自然对接不上。我先给你捋三个最常见的“踩坑点”,你对照着自己的代码看看:
第一个坑:前端没设对“Content-Type”。很多人写Ajax的时候,默认用jQuery的$.ajax,没加contentType: 'application/json'
——这时候浏览器会默认把请求头设为application/x-www-form-urlencoded
(就是表单提交的格式),而你发的是JSON字符串,ThinkPHP拿到这种请求,会把数据放到$_POST
里,但JSON字符串根本不是表单格式,所以$_POST
是空的。我朋友的问题就是这个——他前端写了data: JSON.stringify({name: '张三'})
,但没加contentType,后端拿input('post.name')
自然什么都没有。
第二个坑:后端用错了解析方法。就算前端设对了Content-Type,很多人还是习惯性用input('post.')
或者$_POST
拿数据——但ThinkPHP对“application/json”类型的请求,不会把数据放到$_POST
里,因为$_POST
只处理表单格式的数据。这时候你得用input('json.')
(ThinkPHP5.1+的封装方法),或者原生的json_decode(file_get_contents('php://input'), true)
——我之前帮另一个做电商系统的客户调bug,他后端一直用input('post.goods_id')
,结果拿到的是null,改成input('json.goods_id')
立刻就好了。
第三个坑:跨域导致“OPTIONS预请求”被拦截。如果你的前后端是分离的(比如前端在localhost:8080,后端在localhost:80),浏览器会先发一个“OPTIONS”请求试探后端是否允许跨域——如果后端没处理这个请求,直接返回403或500,你的正式请求根本发不出去。我之前帮一个做小程序的朋友调试,他后端没加跨域中间件,结果Ajax请求一直报“CORS policy”错误,加了允许OPTIONS的配置才解决。
我把这些常见错误整理成了表格,你直接对照着查:
错误现象 | 常见原因 | 解决方法 |
---|---|---|
后端var_dump($_POST)为空 | 前端未设置Content-Type为application/json | 前端Ajax添加contentType: ‘application/json’ |
后端拿到字符串而非数组 | 用了input(‘post.’)而非json解析方法 | 改用input(‘json.’)或json_decode(file_get_contents(‘php://input’), true) |
请求报403/500(跨域) | OPTIONS预请求被拦截 | 后端加跨域中间件,允许OPTIONS请求 |
这里插一句:如果你想确认自己的请求头对不对,可以用Chrome的“开发者工具”——打开“Network” tab,找到你的Ajax请求,看“Request Headers”里有没有Content-Type: application/json
,如果没有,赶紧去前端代码里加。
一步一步来:ThinkPHP接收Ajax JSON的正确操作
说完了“为什么错”,我再给你讲“怎么对”——不管你用的是jQuery、原生JS还是Vue的Axios,不管你是ThinkPHP5还是ThinkPHP6,步骤都差不多,我给你拆成“前端配置”和“后端接收”两部分,每一步都给你讲原理,保证你懂“为什么要这么做”。
不管你用什么前端框架,发JSON数据的Ajax必须满足两个条件:把数据转成JSON字符串+设置Content-Type为application/json。我给你举三个常见的例子:
$.ajax({
url: 'http://yourdomain.com/api/user/save',
type: 'POST',
contentType: 'application/json', // 关键:告诉后端你发的是JSON
data: JSON.stringify({name: '张三', age: 25}), // 关键:把对象转成JSON字符串
success: function(res) {
console.log(res);
}
});
const xhr = new XMLHttpRequest();
xhr.open('POST', 'http://yourdomain.com/api/user/save');
xhr.setRequestHeader('Content-Type', 'application/json'); // 加请求头
xhr.onreadystatechange = function() {
if (xhr.readyState === 4 && xhr.status === 200) {
console.log(JSON.parse(xhr.responseText));
}
};
xhr.send(JSON.stringify({name: '张三', age: 25})); // 发JSON字符串
axios.post('http://yourdomain.com/api/user/save', JSON.stringify({name: '张三', age: 25}), // 转字符串
{
headers: {
'Content-Type': 'application/json' // 设请求头
}
}
).then(res => {
console.log(res.data);
});
为什么要转JSON字符串?因为如果直接发对象,jQuery或Axios会默认把它转成name=张三&age=25
的表单格式,和你要的JSON完全不一样。为什么要设Content-Type?因为后端需要根据这个头来决定“用什么方式解析数据”——ThinkPHP看到application/json
,才会去读php://input
里的JSON字符串,再解析成数组。
前端发对了,后端怎么接?ThinkPHP给了两种方法,你选自己习惯的就行:
方法一:用ThinkPHP封装的input('json.')
(推荐)
ThinkPHP5.1及以上版本,专门加了input('json.')
方法,用来获取JSON格式的请求数据——它会自动帮你做两件事:读取php://input的内容+解析成数组。比如前端发的是{"name":"张三","age":25}
,后端这样写:
// ThinkPHP5.1/6的控制器方法
public function saveUser()
{
// 获取整个JSON对象转成的数组
$userData = input('json.');
// 直接拿里面的字段
$name = input('json.name');
$age = input('json.age');
// 接下来做业务逻辑,比如存数据库
$result = Db::name('user')->insert($userData);
return json(['code' => 200, 'msg' => '保存成功']);
}
这个方法的好处是“不用自己解析”,ThinkPHP帮你处理好了,而且兼容各种版本(只要是5.1以上)。
方法二:用原生PHP的json_decode(file_get_contents('php://input'), true)
(通用)
如果你的ThinkPHP版本低于5.1,或者你想更“底层”一点,可以用这个方法——php://input
是PHP提供的“输入流”,用来读取非表单格式的请求数据(比如JSON、XML)。代码如下:
public function saveUser()
{
// 读取请求体的内容(JSON字符串)
$jsonStr = file_get_contents('php://input');
// 解析成数组(第二个参数true表示转成关联数组)
$userData = json_decode($jsonStr, true);
// 检查解析是否成功(防止前端发的不是合法JSON)
if (is_null($userData)) {
return json(['code' => 400, 'msg' => '数据格式错误']);
}
$name = $userData['name'];
$age = $userData['age'];
// 业务逻辑...
}
这个方法的好处是“通用”——不管你用的是ThinkPHP还是其他框架,甚至原生PHP,都能用。但要注意:如果前端没发JSON字符串,json_decode
会返回null,所以一定要加“解析失败”的判断。
如果你的前后端不在同一个域名下(比如前端是http://localhost:8080
,后端是http://localhost
),肯定会遇到跨域问题——这时候你需要在后端加一个“跨域中间件”,允许前端的请求。我给你讲ThinkPHP6的做法(5.1类似):
第一步:在app/middleware.php
里注册跨域中间件:
// app/middleware.php
return [
// 其他中间件...
appmiddlewareCors::class, // 加这行
];
第二步:创建app/middleware/Cors.php
文件,写中间件逻辑:
<?php namespace appmiddleware;
class Cors
{
public function handle($request, Closure $next)
{
$response = $next($request);
// 允许的域名(可以设为,但生产环境 指定具体域名)
$origin = $request->header('origin', '');
// 允许的请求方法
$methods = 'GET, POST, PUT, DELETE, OPTIONS';
// 允许的请求头
$headers = 'Content-Type, Authorization';
// 设置响应头
$response->header([
'Access-Control-Allow-Origin' => $origin,
'Access-Control-Allow-Methods' => $methods,
'Access-Control-Allow-Headers' => $headers,
'Access-Control-Allow-Credentials' => 'true' // 允许带Cookie的话加这个
]);
// 处理OPTIONS预请求(直接返回204)
if ($request->method() === 'OPTIONS') {
return $response->code(204);
}
return $response;
}
}
这样设置后,前端的OPTIONS请求会被允许,正式的JSON请求也能正常发送了。我之前帮一个做Vue项目的客户配置过这个中间件,他之前的跨域错误立刻就消失了。
最后再给你提个醒:写完代码后,一定要用“Postman”或者“Apifox”测试一下——先模拟前端发一个JSON请求,看后端能不能拿到数据。比如用Postman的话,选“POST”方法,填你的接口地址,在“Body”里选“raw”→“JSON”,输入{"name":"测试","age":18}
,发送后看后端返回的结果。如果后端能拿到name
和age
,说明你成功了!
你按这个方法试了之后,不管是成功还是遇到新问题,都可以在评论区告诉我——我帮你再看看。毕竟调bug这种事,多个人聊聊总能更快解决~
前端发了JSON数据,后端var_dump($_POST)怎么是空的?
这大概率是前端没设对“Content-Type”请求头!你得在Ajax里加一句contentType: ‘application/json’(比如jQuery的$.ajax),而且数据要先用JSON.stringify()转成字符串——因为浏览器默认会把请求头设成表单格式(application/x-www-form-urlencoded),后端收到这种请求,自然不会把JSON数据放到$_POST里,所以var_dump出来是空的。我去年帮做本地生活平台的朋友调这个问题,就是漏了这一步,加完立刻就有数据了。
ThinkPHP里用input(‘post.’)拿不到JSON数据怎么办?
那是因为你用错方法啦!ThinkPHP对“application/json”类型的请求,不会把数据放到post参数里——你得改用input(‘json.’)(ThinkPHP5.1及以上能用),比如要拿name字段就写input(‘json.name’);要是版本低于5.1,就用原生方法:先读php://input的内容(file_get_contents(‘php://input’)),再用json_decode转成数组(记得加第二个参数true,不然是对象)。我之前帮电商客户调“保存商品”的接口,把input(‘post.goods_id’)改成input(‘json.goods_id’),立刻就拿到数据了。
Ajax请求报跨域错误,怎么解决?
这是浏览器的“OPTIONS预请求”被后端拦截了!你得在ThinkPHP里加个跨域中间件:先在app/middleware.php里注册中间件(比如appmiddlewareCors::class),然后在中间件里设置响应头——允许前端的域名(Access-Control-Allow-Origin)、请求方法(比如GET、POST、OPTIONS)、请求头(比如Content-Type),还要把OPTIONS请求直接返回204状态码。我之前帮Vue项目的客户配过这个中间件,设置完跨域错误立刻就消失了。
前端发了JSON,后端解析出来是null怎么回事?
先检查前端是不是真的用JSON.stringify()转了字符串——有时候光传对象没用,得转成JSON格式的字符串;然后看后端解析方法对不对:用json_decode的话,第二个参数要加true(转成关联数组),或者用ThinkPHP的input(‘json.’);另外还要确认前端有没有设对Content-Type——要是没设成application/json,后端根本不会按JSON解析。我之前遇到过一次,前端忘加stringify,结果后端拿到的是“[object Object]”,解析出来自然是null。
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是赞助,收取费用仅维持本站的日常运营所需!
7. 如遇到加密压缩包,请使用WINRAR解压,如遇到无法解压的请联系管理员!
8. 精力有限,不少源码未能详细测试(解密),不能分辨部分源码是病毒还是误报,所以没有进行任何修改,大家使用前请进行甄别!
站长QQ:709466365 站长邮箱:709466365@qq.com