Laravel 5.5使用Passport的API请求为何匹配web路由而非api路由?
兄弟,这个坑我之前也踩过!核心问题出在Laravel的路由加载顺序和你那个兜底路由的贪婪匹配规则上:
Laravel默认是先加载web.php里的所有路由,之后才会加载api.php的路由。而你写的{catchall}路由用了(.*)的正则规则,会匹配任何未被web.php前面路由命中的请求——包括你的API请求。也就是说,你的API请求还没轮到api.php的路由去匹配,就被web.php的兜底路由先截胡返回404了。
1. 调整路由加载顺序(最推荐,改动最小)
Laravel的路由加载逻辑在RouteServiceProvider.php里定义,你只需要把API路由的加载移到Web路由前面,让API请求优先匹配api.php的规则:
打开app/Providers/RouteServiceProvider.php,找到map方法,修改顺序:
public function map() { // 先加载API路由,优先匹配 $this->mapApiRoutes(); // 再加载Web路由 $this->mapWebRoutes(); }
这样一来,所有API请求会先走api.php的路由规则,只有非API请求才会进入web.php的路由匹配流程,兜底路由就不会干扰API了。
2. 给Web兜底路由加排除规则
如果不想调整加载顺序,可以修改web.php里的兜底路由,让它只捕获非API前缀的路径。假设你的API都是/api开头的,给正则加上排除逻辑:
Route::get('{catchall}', ['as' => 'url', 'uses'=>'PagesController@getPage']) ->where('catchall', '^(?!api).*$');
这个正则^(?!api).*$的意思是:只匹配不以api开头的路径,API请求会自动绕过这个兜底路由,去匹配api.php的规则。
3. 给Web路由统一加前缀(适合重构场景)
如果你的项目还在早期,可以给所有Web路由加一个统一前缀(比如/web),让兜底路由只作用于Web路径:
在RouteServiceProvider.php的mapWebRoutes方法里修改:
protected function mapWebRoutes() { Route::middleware('web') ->prefix('web') // 给所有Web路由加前缀 ->namespace($this->namespace) ->group(base_path('routes/web.php')); }
这个方法改动稍大,需要同步调整前端页面的URL,但能彻底隔离Web和API的路由空间。
记得用Postman测试时,确保API请求的URL正确带上了默认的/api前缀(比如GET /api/users),同时确认api.php里的路由定义是正确的,比如:
Route::get('/users', function () { return response()->json(['data' => '正常API响应']); });
内容的提问来源于stack exchange,提问作者Webtect

