success()是渲染HTML跳转模板,返回text/html而非JSON,适用于同步表单提交;json()才返回application/json响应,用于API接口。

success() 是前端跳转模板,不是 JSON 响应
success() 方法本质是渲染一个内置 HTML 模板(如 thinkphp/tpl/dispatch_jump.tpl),里面嵌了一段 JS 脚本执行 window.location.href 或 history.back()。它返回的是 text/html,不是 JSON,浏览器收到后直接显示页面,不会触发 response.json() 解析。
常见错误现象包括:AJAX 请求里调用 success(),结果把跳转 HTML 当作响应体返回给 JS;或因前置输出导致模板被截断,页面白屏;又或者 Nginx 缓存了该 HTML,JS 根本不执行。
- 它不设
Content-Type: application/json,也不调用json_encode() - 不能用于 API 接口,只适合同步表单提交后的提示跳转
- 依赖前端环境,移动端 WebView、某些安全策略下可能静默失败
json() 是纯 JSON 响应,自动设 header 和编码
json() 助手函数会自动设置 Content-Type: application/json; charset=utf-8,调用 json_encode($data, JSON_UNESCAPED_UNICODE),并终止后续流程(类似 exit)。它不渲染任何模板,输出就是裸 JSON 字符串。
你写 return json(['id' => 123]);,得到的就是 {"id":123},前端可直接 res.json() 解析。
立即学习“PHP免费学习笔记(深入)”;
- 必须确保调用前无任何输出(空格、BOM、
echo、未捕获的 warning) - 支持传入状态码:
json($data, 201)→ HTTP 状态码为 201 - 不兼容旧结构?别改框架源码,直接
json(['status' => 'success', 'data' => $data])
别把 success() 当成语义化封装来用
很多人误以为 success('ok', $data) 是 json() 的“增强版”,其实不是:success() 返回固定结构 {"code":1,"msg":"ok","data":{}},但它是 HTML 响应;而 json() 完全自由,结构由你定。
如果你要统一 API 响应格式,应该自己封装基类方法,比如:
protected function apiSuccess($data = null, $msg = '操作成功') {
return json(['success' => true, 'message' => $msg, 'data' => $data]);
}
- 不要在 API 控制器里混用
success()和json() -
show()同样是 HTML 渲染,绝不可用于接口 - 想保留 success() 的 UI 效果?前端收 JSON 后自己用
ElMessage或Toast提示再跳转
最容易被忽略的点:请求体解析和响应类型是两回事
有人以为“我发的是 application/json 请求,那 success() 就该自动变 JSON”,这是典型误解。TP6 中请求类型($request->isJson())只影响参数读取方式($request->json() vs $request->input()),和响应类型完全无关。
也就是说:即使你用 Axios 发 Content-Type: application/json,只要控制器里写 return success(...),返回的仍是 HTML;反之,GET 请求也能用 json() 返回 JSON。
- 响应类型只由你写的
return语句决定,和请求头无关 - 调试时用
dump(headers_sent())或浏览器 Network 面板看实际Content-Type - TP6.1+ 的
$request->withJson(true)只影响输入解析,不影响输出



















