Mock接口返回数据不生效,需确保APP_DEBUG=true且APP_ENV=testing,App::debug()返回true,Mock注册在路由加载前完成,Route::mock()严格匹配HTTP方法与路由规则,并复用响应实例保留CORS头。

Mock接口返回数据不生效,检查App::debug()和环境配置是否匹配
ThinkPHP的Mock功能依赖调试模式开启且环境为testing,否则think\facade\App::mock()或路由级Mock会被忽略。常见现象是写了Mock逻辑但接口仍走真实业务代码。
- 确认
.env中APP_DEBUG=true且APP_ENV=testing(不能是test或dev) -
App::debug()必须返回true,某些CI环境会强制关闭调试,需在public/index.php入口手动补define('APP_DEBUG', true) - Mock注册必须在路由注册前完成,推荐放在
app/provider.php或app/common.php顶部
用Route::mock()拦截API请求时,路径匹配要带完整HTTP方法和前缀
ThinkPHP 6.1+ 的Route::mock()不是简单替换URL,而是按「方法+路由规则」双匹配,漏掉任一条件都会失效。
- 示例:想Mock
GET /api/v1/user/123,写法必须是Route::mock('get', 'api/v1/user/:id', function($id){ return json(['id'=>$id]); }); - 如果全局启用了
url_route_must,则路由规则里不能省略模块/控制器前缀,比如'api/v1/user/:id'实际可能对应'api.v1.user.read',此时需用命名路由Mock:Route::mock('get', 'user_read', ...) - 注意
Route::mock()不支持正则路由变量以外的动态段,如:id\d+需改用:id再在闭包里校验
think-mock扩展与原生Mock混用导致闭包执行两次
第三方think-mock包内部也调用Route::mock(),若同时使用原生Mock和该扩展,相同路由会被重复注册,造成响应体被序列化两次(如{"code":0}{"code":0})。
- 优先用原生
Route::mock(),除非需要其数据模板语法;think-mock适合大量静态JSON文件场景 - 检查
composer.json是否同时存在topthink/think-orm(v3+)和topthink/think-mock,后者已停止维护,v6.3+建议直接用think\facade\Route::mock() - 调试时加日志:
Route::mock(..., function() { \think\facade\Log::info('mock hit'); return json([...]); });,观察日志出现次数
Mock响应头丢失、CORS报错,是因为没继承原始响应对象
直接return json()或return response()->json()会绕过中间件,导致Access-Control-Allow-Origin等头被清空,前端跨域失败。
立即学习“PHP免费学习笔记(深入)”;
- 正确做法是复用当前请求的响应实例:
return \think\Response::create(['data'=>[]])->header($_SERVER['HTTP_ORIGIN']??'')->send(); - 更稳妥的是在Mock闭包里调用
\think\facade\Response::create()并显式设置头:Response::create([...])->header('Access-Control-Allow-Origin','*')->header('Content-Type','application/json') - 若项目用了
think-cors中间件,Mock必须在中间件之后触发,即不要在app/middleware.php之前注册Mock
.env里的APP_ENV必须在think\App初始化前生效,而Mock注册又必须在Route::load()之后;这两处时间差不到10行代码,但错一个就全盘无效。



















