ThinkPHP路由不返回JSON需禁用模板渲染并显式调用json(),RESTful路由应分组定义,控制器末尾必须return json($data),避免使用fetch()等视图方法。

ThinkPHP 路由不返回 JSON?关掉模板渲染和默认控制器
ThinkPHP 默认走 index/index 控制器并尝试渲染 HTML 模板,前后端分离下这会直接报 500 或输出乱码。必须显式禁用模板机制,让接口只返回纯 JSON。
在路由配置(route/route.php)中,不要用 Route::rule('/*', 'index/index') 这类兜底写法;而是按资源定义 RESTful 路由:
Route::group('api', function () {
Route::post('login', 'Auth/login');
Route::get('user', 'User/info')->middleware('auth');
})->cross(false);
每个控制器方法末尾必须显式调用 json(),不能依赖自动输出:
public function login()
{
$data = $this->request->param(); // 注意:仅对表单有效
return json(['token' => 'xxx', 'code' => 200]);
}
- 控制器继承
think\Controller即可,无需额外 base 类 - 别在控制器里调
$this->fetch()或任何视图相关方法 - 如果用了中间件做统一响应封装,确保它不拦截或覆盖
json()返回值
Vue 发 POST 请求,ThinkPHP 收不到参数?分清 param() 和 input()
this->request->param() 只解析 application/x-www-form-urlencoded 和 multipart/form-data;而 Axios 默认发的是 application/json,这时 param() 必然为空。
立即学习“PHP免费学习笔记(深入)”;
两种解法,选其一即可:
- 前端改用表单格式:在 Axios 请求中加
transformRequest+qs.stringify(),并手动设Content-Type: application/x-www-form-urlencoded - 后端改用原始读取:
input('username')或json_decode($this->request->getContent(), true)
推荐后者——更符合 API 设计直觉,也避免前端重复处理序列化:
Element Plus Vue3 桌面组件库。在开发 Vue 3.x 页面时调用,使用 Element Plus 组件(如 el-button、el-input、el-form、el-table 等)。
public function login()
{
$raw = $this->request->getContent();
$data = json_decode($raw, true) ?: [];
$username = $data['username'] ?? '';
$password = $data['password'] ?? '';
// 后续逻辑...
}
注意:$this->request->input() 在 TP6/8 中已废弃,别用。
跨域请求被拦、OPTIONS 404?用 think-cors 扩展,别手写 header
手动在中间件里写 $response->header('Access-Control-Allow-Origin', '*') 看似简单,但漏掉 OPTIONS 预检、credentials 冲突、expose-headers 等细节,上线就崩。
正确路径是统一用官方扩展:
composer require topthink/think-cors
然后在 config/cors.php 中配死域名(生产环境严禁用 *):
return [
'origin' => ['https://your-vue-app.com'],
'allow_credentials'=> true,
'allow_methods' => ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
'allow_headers' => ['Content-Type', 'Authorization', 'X-Requested-With'],
];
- 若前端用 JWT,
allow_credentials可设为false,改用Authorization: Bearer xxx传 token - Vue 的 Axios 请求必须加
withCredentials: true(仅当后端允许 credentials 时才需要) - TP 默认没注册 OPTIONS 路由,但 think-cors 会自动拦截并返回 204,不用额外补空路由
验证码总校验失败?Session 在跨域下根本不可用
前端请求 /captcha 图片,后端往 Session 写 captcha.key;提交时再从 Session 读——这套逻辑在跨域下必然失效:浏览器不发 Cookie,Session ID 断连,$this->session->get() 永远是 null。
必须放弃 Session 绑定,改用可显式传递的唯一 ID:
- 生成验证码接口返回
{captcha_id: "abc123", image: "data:image/png;base64,..."} - 前端把
captcha_id存进表单 hidden 字段或请求头 - 校验接口接收
captcha_id和用户输入的code,查 Redis keycaptcha:abc123 - 查完立刻
DEL captcha:abc123,TTL 设 120 秒足够
别用文件或数据库存验证码——Redis 原子性好、过期自动清理、性能无压力。ThinkPHP 自带 cache('redis') 就能直接用。


















