真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

Laravel中處理OPTIONS請求的原理是什么

Laravel中處理OPTIONS請求的原理是什么,針對這個問題,這篇文章詳細介紹了相對應的分析和解答,希望可以幫助更多想解決這個問題的小伙伴找到更簡單易行的方法。

成都創(chuàng)新互聯(lián)是專業(yè)的建華網(wǎng)站建設(shè)公司,建華接單;提供成都網(wǎng)站設(shè)計、網(wǎng)站制作,網(wǎng)頁設(shè)計,網(wǎng)站設(shè)計,建網(wǎng)站,PHP網(wǎng)站建設(shè)等專業(yè)做網(wǎng)站服務;采用PHP框架,可快速的進行建華網(wǎng)站開發(fā)網(wǎng)頁制作和功能擴展;專業(yè)做搜索引擎喜愛的網(wǎng)站,專業(yè)的做網(wǎng)站團隊,希望更多企業(yè)前來合作!

1. 問題描述

Laravel處理OPTIONS方式請求的機制是個謎。

假設(shè)我們請求的URL是http://localhost:8080/api/test,請求方式是OPTIONS。

如果請求的URL不存在相關(guān)的其它方式(如GETPOST)的請求,則會返回404 NOT FOUND的錯誤。

如果存在相同URL的請求,會返回一個狀態(tài)碼為200的成功響應,但沒有任何額外內(nèi)容。

舉例而言,在路由文件routes/api.php中如果存在下面的定義,則以OPTIONS方式調(diào)用/api/test請求時,返回狀態(tài)碼為200的成功響應。

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

但同時通過分析可以發(fā)現(xiàn),這個OPTIONS請求不會進到此api路由文件的生命周期內(nèi),至少該GET請求所在路由文件api所綁定的中間件是沒有進入的。

此時如果手動添加一個OPTIONS請求,比如:

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

則至少會進入該GET請求所在路由文件api綁定的中間件,可以在相關(guān)handle函數(shù)中捕獲到這個請求。

2. 分析源碼

通過仔細查看Laravel的源碼,發(fā)現(xiàn)了一些端倪。

在文件vendor/laravel/framework/src/Illuminate/Routing/RouteCollection.php的第159行左右,源碼內(nèi)容如下:

        $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. 首先根據(jù)當前HTTP方法(GET/POST/PUT/...)查找是否有匹配的路由,如果有(if(! is_null($route))條件成立),非常好,綁定后直接返回,繼續(xù)此后的調(diào)用流程即可;

2. 否則,根據(jù)$request的路由找到可能匹配的HTTP方法(即URL匹配,但是HTTP請求方式為其它品種的),如果count($others) > 0)條件成立,則繼續(xù)進入$this->getRouteForMethods($request, $others);方法;

3. 否則拋出NotFoundHttpException,即上述說到的404 NOT FOUND錯誤。

倘若走的是第2步,則跳轉(zhuǎn)文件的234行,可看到函數(shù)邏輯為:

    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,則返回狀態(tài)碼為200的正確響應(但是沒有添加任何header信息),否則返回一個methodNotAllowed狀態(tài)碼為405的錯誤(即請求方式不允許的情況)。

此處Laravel針對OPTIONS方式的HTTP請求處理方式已經(jīng)固定了,這樣就有點頭疼,不知道在哪里添加代碼針對OPTIONS請求的header進行處理。最笨的方法是對跨域請求的每一個GETPOST請求都撰寫一個同名的OPTIONS類型的路由。

3. 解決辦法

解決方案有兩種,一種是添加中間件,一種是使用通配路由匹配方案。

總體思想都是在系統(tǒng)處理OPTIONS請求的過程中添加相關(guān)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函數(shù),就已經(jīng)返回了。

因此我們添加的中間件,需要添加到$middleware數(shù)組中,不能添加到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請求的處理內(nèi)容是添加多個header內(nèi)容,可根據(jù)實際需要修改相關(guān)處理邏輯:

$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請求都得到了相關(guān)處理。

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-]|/)+']);

關(guān)于Laravel中處理OPTIONS請求的原理是什么問題的解答就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道了解更多相關(guān)知識。


網(wǎng)站欄目:Laravel中處理OPTIONS請求的原理是什么
本文鏈接:http://weahome.cn/article/jjjhpp.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部