thinkphp 6 中 response()->json() 必须 return(控制器)或 ->send()(中间件等),否则响应体为空;需避免前置输出、bom、错误日志及 viewinit 中间件干扰,并确保 content-type 正确。

response()调用后没send()也没return
ThinkPHP 6 的 response() 默认只构建响应对象,不自动输出。你在中间件、钩子或非控制器逻辑里写了 response()->json(['code'=>0]),但没 ->send(),也没 return,响应体就一定是空的。
常见现象:curl -I 看到状态码是 200,但 curl -s 拿不到任何内容;浏览器打开接口返回空白页;Postman 显示 “no response body”。
- 在控制器方法中,必须以
return response()->json(...)结尾,框架才会自动调用send() - 在中间件、
App::before()、事件监听器等非控制器场景,必须显式加->send(),例如:response()->json(['msg'=>'ok'])->send() - 调用
->send()后再echo或输出其他内容,会触发 “headers already sent” 错误
前置输出导致 JSON 损坏
哪怕一个空格、BOM 头、var_dump()、未捕获的 Notice(比如访问未定义数组键),都会让 json() 或 response()->json() 前产生输出,JSON 格式直接损坏,浏览器报 Unexpected token in JSON at position 0。
- 检查所有 PHP 文件是否为「UTF-8 无 BOM」格式,尤其
config/、route/、middleware/目录下的文件 - 禁用控制器/中间件里任何
echo、print_r()、var_dump() - 避免未定义变量或数组键触发 PHP Warning/Notice,例如
$data['name']前没判断isset($data['name']) - 微信支付回调等特殊接口,连日志
Log::info()都不能写在response()之前,否则响应体含不可见字符,微信会持续重发
Content-Type 不匹配或缺失
响应头不是 application/json; charset=utf-8,前端 fetch().json() 就会解析失败。ThinkPHP 的 json() 方法自动设对了类型,但 raw()、content()、view() 包裹的响应默认不是 JSON 类型。
-
response()->json($data)✅ 自动设Content-Type: application/json; charset=utf-8 -
response()->raw(json_encode($data))❌ 默认是text/html,必须手动加->contentType('application/json; charset=utf-8') -
response(view('api.success', $data))❌ 返回的是 HTML 字符串,Content-Type 是text/html,即使内容是 JSON 字符也不行 - 自定义异常处理器的
render()方法,必须返回Response实例,不能直接return view(...),否则没有 Content-Type
被 ViewInit 中间件拦截
如果你启用了模板自动渲染(比如全局注册了 ViewInit 中间件),它会把控制器返回的数组或响应对象当成模板变量处理,强行套上 HTML 模板,最终返回的是带 HTML 标签的字符串,而不是纯 JSON。
- 现象:响应体是
...,Content-Type 是text/html - 解决方式:在路由定义里禁用该中间件,例如
Route::get('api/user', 'User/get')->withoutMiddleware(\think\middleware\ViewInit::class) - 更稳妥的做法是统一用
return json($data),它绕过模板链,直接走 JSON 响应通道
json() 那一行,要顺藤摸瓜查清输出前有没有 echo、有没有日志、有没有中间件干扰、有没有 BOM。php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











