成人午夜视频全免费观看高清-秋霞福利视频一区二区三区-国产精品久久久久电影小说-亚洲不卡区三一区三区一区

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

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

成都創(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)站服務(wù);采用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的成功響應(yīng),但沒有任何額外內(nèi)容。

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

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的正確響應(yīng)(但是沒有添加任何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,只有路由匹配上對應(yīng)群組模式的才會通過這部分。

這是總中間件$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文件:

<?php

namespace App\Http\Middleware;
use Closure;
class PreflightResponse
{
    /**
    * Handle an incoming request.
    *
    * @param  \Illuminate\Http\Request  $request
    * @param  \Closure  $next
    * @param  string|null  $guard
    * @return mixed
    */
    public function handle($request, Closure $next, $guard = null)
    {
        if($request->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方式的請求可以撰寫如下路由響應(yīng):

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)知識。

當前題目:Laravel中處理OPTIONS請求的原理是什么
網(wǎng)頁路徑:http://jinyejixie.com/article38/jjjhpp.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供微信公眾號、網(wǎng)頁設(shè)計公司、品牌網(wǎng)站制作、標簽優(yōu)化、網(wǎng)站建設(shè)、企業(yè)網(wǎng)站制作

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

成都網(wǎng)頁設(shè)計公司
龙泉市| 宝丰县| 普定县| 黑龙江省| 剑阁县| 昆明市| 会宁县| 内丘县| 黑河市| 金山区| 甘孜| 垣曲县| 曲靖市| 林州市| 康马县| 永丰县| 囊谦县| 金寨县| 马龙县| 博湖县| 苍南县| 芒康县| 东至县| 成武县| 惠水县| 霍城县| 库车县| 油尖旺区| 偃师市| 康乐县| 定边县| 广州市| 武定县| 巴林右旗| 中牟县| 河曲县| 姜堰市| 无锡市| 灯塔市| 武川县| 澎湖县|