Route::rule() 的 method 参数才是真正的请求方式过滤开关,Route::get()/post() 仅注册路由不校验方法,需开启 url_route_must=true 才生效。

Route::rule() 的 method 参数才是真正的请求方式过滤开关
只用 Route::get() 或 Route::post() 注册路由,**不会阻止其他 HTTP 方法访问**。比如写 Route::post('/api/login', 'LoginController@login'),浏览器直接 GET /api/login 仍能成功执行——这不是 bug,是设计行为。
真正起作用的是 Route::rule() 的第三个参数 method,它强制校验原始请求方法(或 _method 参数,取决于配置):
-
Route::rule('/api/login', 'LoginController@login', 'POST')—— 仅允许 POST -
Route::rule('/api/user', 'UserController@save', ['POST', 'PUT'])—— 允许多个方法 - 数组定义方式必须显式写
'method' => 'POST',不能省略
关键前提是:项目配置中 'url_route_must' => true 必须开启(默认已开),否则 method 校验会被跳过。
为什么 Route::post() 看似没生效?检查是否走了“规则路由”路径
Route::post() 底层确实调用了 Route::rule(..., 'POST'),但它只在“规则路由”模式下触发 method 检查。如果你启用了兼容模式('url_common' => true)或关闭了 'url_route_must',框架会退化为按 PATHINFO 解析,直接忽略 method。
立即学习“PHP免费学习笔记(深入)”;
验证方式:
- 打开
config/route.php,确认存在'url_route_must' => true - 确保没在全局或分组路由外误用了
Route::post();若用了Route::domain()或Route::group(),method限制必须写在闭包内部 - 注意:RESTful 资源路由(
Route::resource())生成的规则自带 method,但若开启'var_method' => '_method',则实际校验的是_method参数值,不是原始请求头
控制器里 $this->request->isPost() 是补救,不是替代
路由层 method 校验失败后,请求才会进控制器。所以 $this->request->isPost() 或 $this->request->method() 只能做二次判断,无法替代路由约束。
典型风险场景:
- 登录接口被 GET 撞入,可能意外读取 session 或返回敏感信息
- 删除接口(
DELETE /user/123)被 POST 调用,导致逻辑错乱 - 前端调试时手动构造 URL,绕过 JS 层 method 控制,直击后端
正确做法是:**路由层拦截所有非法 method,控制器只处理已通过校验的请求**。把 isPost() 当兜底可以,但不能依赖它做主控。
跨域 + method 限制组合时,OPTIONS 预检请求要单独处理
当接口同时启用 allowCrossDomain() 和 method 限制时,浏览器发的 OPTIONS 预检请求会先被路由匹配。如果没配好,它可能因不满足 method(比如要求 POST 却收到 OPTIONS)而被拒绝,导致跨域失败。
稳妥方案是:在入口文件 public/index.php 顶层拦截 OPTIONS:
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS');
header('Access-Control-Allow-Headers: X-Token, Content-Type, Authorization');
exit;
}
这样 OPTIONS 直接返回,不走路由和中间件,避免与 method 校验冲突。注意:自定义跨域中间件里也要同步更新 Access-Control-Allow-Headers,否则带 X-Token 的请求仍会失败。
method 限制看似简单,但实际生效依赖路由模式、配置开关、分组嵌套和跨域协同。最容易被忽略的是 url_route_must 配置项——它一关,整个 method 过滤就形同虚设。


















