千家信息网

Laravel中处理OPTIONS请求的原理是什么

发表于:2026-11-01 作者:千家信息网编辑
千家信息网最后更新 2026年11月01日,Laravel中处理OPTIONS请求的原理是什么,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。1. 问题描述Laravel处理OP
千家信息网最后更新 2026年11月01日Laravel中处理OPTIONS请求的原理是什么

Laravel中处理OPTIONS请求的原理是什么,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。

1. 问题描述

Laravel处理OPTIONS方式请求的机制是个谜。

假设我们请求的URL是http://localhost:8080/api/test,请求方式是OPTIONS。

如果请求的URL不存在相关的其它方式(如GET或POST)的请求,则会返回404 NOT FOUND的错误。

如果存在相同URL的请求,会返回一个状态码为200的成功响应,但没有任何额外内容。

举例而言,在路由文件routes/api.php中如果存在下面的定义,则以OPTIONS方式调用/api/test请求时,返回状态码为200的成功响应。

Route::get('/test', 'TestController@test');

但同时通过分析可以发现,这个OPTIONS请求不会进到此api路由文件的生命周期内,至少该GET请求所在路由文件api所绑定的中间件是没有进入的。

此时如果手动添加一个OPTIONS请求,比如:

Route::get('/test', 'TestController@test');Route::options('/test', function(Request $request) {    return response('abc');});

则至少会进入该GET请求所在路由文件api绑定的中间件,可以在相关handle函数中捕获到这个请求。

2. 分析源码

通过仔细查看Laravel的源码,发现了一些端倪。

在文件vendor/laravel/framework/src/Illuminate/Routing/RouteCollection.php的第159行左右,源码内容如下:

        $routes = $this->get($request->getMethod());        // First, we will see if we can find a matching route for this current request        // method. If we can, great, we can just return it so that it can be called        // by the consumer. Otherwise we will check for routes with another verb.        $route = $this->matchAgainstRoutes($routes, $request);        if (! is_null($route)) {            return $route->bind($request);        }        // If no route was found we will now check if a matching route is specified by        // another HTTP verb. If it is we will need to throw a MethodNotAllowed and        // inform the user agent of which HTTP verb it should use for this route.        $others = $this->checkForAlternateVerbs($request);        if (count($others) > 0) {            return $this->getRouteForMethods($request, $others);        }        throw new NotFoundHttpException;

这里的逻辑是:

1. 首先根据当前HTTP方法(GET/POST/PUT/...)查找是否有匹配的路由,如果有(if(! is_null($route))条件成立),非常好,绑定后直接返回,继续此后的调用流程即可;

2. 否则,根据$request的路由找到可能匹配的HTTP方法(即URL匹配,但是HTTP请求方式为其它品种的),如果count($others) > 0)条件成立,则继续进入$this->getRouteForMethods($request, $others);方法;

3. 否则抛出NotFoundHttpException,即上述说到的404 NOT FOUND错误。

倘若走的是第2步,则跳转文件的234行,可看到函数逻辑为:

    protected function getRouteForMethods($request, array $methods)    {        if ($request->method() == 'OPTIONS') {            return (new Route('OPTIONS', $request->path(), function () use ($methods) {                return new Response('', 200, ['Allow' => implode(',', $methods)]);            }))->bind($request);        }        $this->methodNotAllowed($methods);    }

判断如果请求方式是OPTIONS,则返回状态码为200的正确响应(但是没有添加任何header信息),否则返回一个methodNotAllowed状态码为405的错误(即请求方式不允许的情况)。

此处Laravel针对OPTIONS方式的HTTP请求处理方式已经固定了,这样就有点头疼,不知道在哪里添加代码针对OPTIONS请求的header进行处理。最笨的方法是对跨域请求的每一个GET或POST请求都撰写一个同名的OPTIONS类型的路由。

3. 解决办法

解决方案有两种,一种是添加中间件,一种是使用通配路由匹配方案。

总体思想都是在系统处理OPTIONS请求的过程中添加相关header信息。

3.1 中间件方案

在文件app/Http/Kernel.php中,有两处可以定义中间件。

第一处是总中间件$middleware,任何请求都会通过这里;第二处是群组中间件middlewareGroups,只有路由匹配上对应群组模式的才会通过这部分。

这是总中间件$middleware的定义代码:

    protected $middleware = [        \Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,        \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,        \App\Http\Middleware\TrimStrings::class,        \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,        \App\Http\Middleware\TrustProxies::class,    ];

这是群组中间件$middlewareGroups的定义代码:

    /**    * The application's route middleware groups.    *    * @var array    */    protected $middlewareGroups = [        'web' => [            \App\Http\Middleware\EncryptCookies::class,            \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,            \Illuminate\Session\Middleware\StartSession::class,            // \Illuminate\Session\Middleware\AuthenticateSession::class,            \Illuminate\View\Middleware\ShareErrorsFromSession::class,            \App\Http\Middleware\VerifyCsrfToken::class,            \Illuminate\Routing\Middleware\SubstituteBindings::class,        ],        'api' => [            'throttle:60,1',            'bindings',            \Illuminate\Session\Middleware\StartSession::class,        ],    ];

由于群组路由中间件是在路由匹配过程之后才进入,因此之前实验中提及的OPTIONS请求尚未通过此处中间件的handle函数,就已经返回了。

因此我们添加的中间件,需要添加到$middleware数组中,不能添加到api群组路由中间件中。

在app/Http/Middleware文件夹下新建PreflightResponse.php文件:

getMethod() === 'OPTIONS'){            $origin = $request->header('ORIGIN', '*');            header("Access-Control-Allow-Origin: $origin");            header("Access-Control-Allow-Credentials: true");            header('Access-Control-Allow-Methods: POST, GET, OPTIONS, PUT, DELETE');            header('Access-Control-Allow-Headers: Origin, Access-Control-Request-Headers, SERVER_NAME, Access-Control-Allow-Headers, cache-control, token, X-Requested-With, Content-Type, Accept, Connection, User-Agent, Cookie, X-XSRF-TOKEN');        }        return $next($request);    }}

其中这里针对OPTIONS请求的处理内容是添加多个header内容,可根据实际需要修改相关处理逻辑:

$origin = $request->header('ORIGIN', '*');header("Access-Control-Allow-Origin: $origin");header("Access-Control-Allow-Credentials: true");header('Access-Control-Allow-Methods: POST, GET, OPTIONS, PUT, DELETE');header('Access-Control-Allow-Headers: Origin, Access-Control-Request-Headers, SERVER_NAME, Access-Control-Allow-Headers, cache-control, token, X-Requested-With, Content-Type, Accept, Connection, User-Agent, Cookie, X-XSRF-TOKEN');

至此,所有OPTIONS方式的HTTP请求都得到了相关处理。

3.2 通配路由匹配方案

如果不使用中间件,查询Laravel官方文档Routing,可知如何在路由中使用正则表达式进行模式匹配。

Route::get('user/{id}/{name}', function ($id, $name) {    //})->where(['id' => '[0-9]+', 'name' => '[a-z]+']);

类似的,可以撰写针对OPTIONS类型请求的泛化处理路由条件:

Route::options('/{all}', function(Request $request) {     return response('options here!');})->where(['all' => '([a-zA-Z0-9-]|/)+']);

*注:这里正则表达式中不能使用符号*

因此,针对跨域问题,对于OPTIONS方式的请求可以撰写如下路由响应:

Route::options('/{all}', function(Request $request) {    $origin = $request->header('ORIGIN', '*');    header("Access-Control-Allow-Origin: $origin");    header("Access-Control-Allow-Credentials: true");    header('Access-Control-Allow-Methods: POST, GET, OPTIONS, PUT, DELETE');    header('Access-Control-Allow-Headers: Origin, Access-Control-Request-Headers, SERVER_NAME, Access-Control-Allow-Headers, cache-control, token, X-Requested-With, Content-Type, Accept, Connection, User-Agent, Cookie');})->where(['all' => '([a-zA-Z0-9-]|/)+']);

关于Laravel中处理OPTIONS请求的原理是什么问题的解答就分享到这里了,希望以上内容可以对大家有一定的帮助,如果你还有很多疑惑没有解开,可以关注行业资讯频道了解更多相关知识。

路由 中间件 方式 处理 文件 内容 方法 问题 方案 状态 代码 函数 条件 源码 逻辑 错误 分析 原理 成功 信息 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 咖啡豆 上海喔噻互联网科技有限公司 互联网科技有限公司经营范围 互联网下的科技发展 没上市的科技互联网公司 互联网 科技创新 青岛互联网科技公司 互联网金融科技创新 易通互联网络科技有限公司 科技互联网创业计划书 老年人脱离互联网科技的作文 互联网科技寓意 成都互联网科技公司100强 互联网科技人工智能实验室 徐州市互联网科技有限公司 广东工业互联网大赛深圳学泰科技 全球科技与互联网公司市值变化 江苏互联网智能科技产品出厂价 伍佰万互联网科技是干嘛的 高科技和互联网的现代国家 互联网是不是新科技 山东吉时兔互联网科技有限公司 长沙茂晟互联网科技有限公司 南博望互联网科技有限公司 互联网营销推广黑科技 广州有谷有贝互联网科技有限公司 科技互联网行业投资研究 广西科技产业互联网是什么 互联网科技新闻 北京瑞云互联网科技有限公司
0