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

成都創新互聯是專業的建華網站建設公司,建華接單;提供成都網站設計、網站制作,網頁設計,網站設計,建網站,PHP網站建設等專業做網站服務;采用PHP框架,可快速的進行建華網站開發網頁制作和功能擴展;專業做搜索引擎喜愛的網站,專業的做網站團隊,希望更多企業前來合作!
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函數中捕獲到這個請求。
通過仔細查看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類型的路由。
解決方案有兩種,一種是添加中間件,一種是使用通配路由匹配方案。
總體思想都是在系統處理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文件:
<?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請求的處理內容是添加多個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請求的原理是什么問題的解答就分享到這里了,希望以上內容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關注創新互聯行業資訊頻道了解更多相關知識。
當前題目:Laravel中處理OPTIONS請求的原理是什么
網頁路徑:http://www.yijiale78.com/article38/jjjhpp.html
成都網站建設公司_創新互聯,為您提供微信公眾號、網頁設計公司、品牌網站制作、標簽優化、網站建設、企業網站制作
聲明:本網站發布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創新互聯