天天看點

laravel-cors 中間件解決跨域問題

跨域的請求

出于安全性的原因,浏覽器會限制 Script 中的跨域請求。由于 XMLHttpRequest 遵循同源政策,所有使用 XMLHttpRequest 構造 HTTP 請求的應用隻能通路自己的域名,如果需要構造跨域的請求,那麼開發者需要配合浏覽器做出一些允許跨域的配置。

W3C 應用工作組推薦了一種跨資源共享的機制,這種機制讓 Web 應用伺服器能支援跨站通路控制,進而使得安全的進行跨站資料傳輸成為可能,該機制通過幾種方式來對原有模式進行了擴充:

  • 響應的頭部應該追加 Access-Control-Allow-Orign,用來表明哪些請求源被允許通路資源内容
  • 浏覽器會對請求源和響應中的值進行比對驗證
  • 對于跨域的請求,浏覽器會預發送一個非簡單方式的請求,來判斷給定資源是否準備接受跨域資源通路
  • 服務端應用通過檢查請求頭部的 Orign 來判定請求是否跨域。跨源資源共享标準

跨源資源共享标準

  跨源資源共享标準通過新增一系列 HTTP 頭,讓伺服器能聲明哪些來源可以通過浏覽器通路該伺服器上的資源。另外,對哪些會對伺服器資料造成破壞性響應的 HTTP 請求方法(特别是 GET 以外的 HTTP 方法,或者搭配某些 MIME 類型的 POST 請求),标準強烈要求浏覽器必須先以 OPTIONS 請求方式發送一個預請求(preflight request),進而擷取知伺服器端對跨源請求所支援 HTTP 方法。在确認伺服器允許跨源請求的情況下,以實際的 HTTP 請求方法發送那個真正的請求。伺服器端也可以通知用戶端,是不是需要随同請求一起發送信用資訊(包括 Cookies 和 HTTP 認證相關資料)。

跨源共享标準需要浏覽器和服務端共同配合才能完成,目前浏覽器廠商已經可以将請求部分自動完成,是以跨源資源通路的重點還是在于伺服器端。

下面列出一些标準中可用的響應頭和請求頭。

Response Header

  • Access-Control-Allow-Origin : 指明哪些請求源被允許通路資源,值可以為 "*","null",或者單個源位址。
  • Access-Control-Allow-Credentials : 指明當請求中省略 creadentials 辨別時響應是否暴露。對于預請求來說,它表明實際的請求中可以包含使用者憑證。
  • Access-Control-Expose-Headers : 指明哪些頭資訊可以安全的暴露給 CORS API 規範的 API。
  • Access-Control-Max-Age : 指明預請求可以在預請求緩存中存放多久。
  • Access-Control-Allow-Methods : 對于預請求來說,哪些請求方式可以用于實際的請求。
  • Access-Control-Allow-Headers : 對于預請求來說,指明了哪些頭資訊可以用于實際的請求中。
  • Origin : 指明預請求或者跨域請求的來源。
  • Access-Control-Request-Method : 對于預請求來說,指明哪些預請求中的請求方式可以被用在實際的請求中。
  • Access-Control-Request-Headers : 指明預請求中的哪些頭資訊可以用于實際的請求中。

Request Header

  • Origin : 表明發送請求或預請求的來源。
  • Access-Control-Request-Method : 在發送預請求時帶該請求頭,表明實際的請求将使用的請求方式。
  • Access-Control-Request-Headers : 在發送預請求時帶有該請求頭,表明實際的請求将攜帶的請求頭。

中間件

在 Laravel 中允許跨域請求,我們可以在app/Http/Middleware/檔案夾下建構一個追加響應的中間件Cors.php,用來添加專門處理跨域的請求的響應頭:

<?php
namespace App\Http\Middleware;

use Closure;
use Response;
class Cors {

    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {

        $response = $next($request);
        $response->header('Access-Control-Allow-Origin', '*');
        $response->header('Access-Control-Allow-Headers', 'Origin, Content-Type, Cookie, Accept');
        $response->header('Access-Control-Allow-Methods', 'GET, POST, PATCH, PUT, OPTIONS');
        $response->header('Access-Control-Allow-Credentials', 'false');
        return $response;
    }

}
           

使用中間件

在app/Http/Kernel.php檔案中protected $routeMiddleware處增加'cors' => \App\Http\Middleware\Cors::class,。

laravel-cors 中間件解決跨域問題

需要跨域請求的路由:

Route::group(['middleware'=>'cors'], function() {
    Route::any('/send','[email protected]');
});
           

其中有以下需要注意的地方:

  • 對于跨域通路并需要伴随認證資訊的請求,需要在 XMLHttpRequest 執行個體中指定 withCredentials 為 true。
  • 這個中間件你可以根據自己的需求進行建構,如果需要在請求中伴随認證資訊(包含 cookie,session)那麼你就需要指定 Access-Control-Allow-Credentials 為 true, 因為對于預請求來說如果你未指定該響應頭,那麼浏覽器會直接忽略該響應。
  • 在響應中指定 Access-Control-Allow-Credentials 為 true 時,Access-Control-Allow-Origin 不能指定為 *
  • 後置中間件隻有在正常響應時才會被追加響應頭,而如果出現異常,這時響應是不會經過中間件的。

縱然世間炎涼百态!我自依舊初心不改!!

su先生給你加油哦!!!