跨域資源共享 CORS (Cross-origin resource sharing) 是一個 W3C 標準

這裡主要針對 php (Laravel) 以及 nginx 如何設置 CORS 進行說明

以及 Laravel 5.5 之後的版本自定義 cros Middleware 踩過的坑進行紀錄

首先,先看一般原生PHP設定 cors 的方式

PHP 設置 cors header

這裡是常見的設定方式:

<?php
  header("Access-Control-Allow-Origin: *");
  header("Access-Control-Allow-Methods: *");
  header("Access-Control-Allow-Headers: Origin, Methods, Content-Type");

Access-Control-Allow-Origin : 允許的域名,*代表全部 Access-Control-Allow-Methods : 允許跨域請求的方法 (GET, POST, PUT, DELETE..),*代表全部 Access-Control-Allow-Headers : 允許Header夾帶的訊息參數 Access-Control-Allow-Credentials : 允許發送 cookie (布林值)

JWT 跨域 CORS 請求問題

在使用 JWT Header夾帶 token 跨域請求時,遇到了下列問題

Access to XMLHttpRequest at 'xxx' from origin 'xxx' has been blocked by CORS policy: Request header field Authorization is not allowed by Access-Control-Allow-Headers in preflight response.

檢查原始的 cors 設定如下:

<?php 
  header("Access-Control-Allow-Origin: *");
  header("Access-Control-Allow-Methods: *");
  header("Access-Control-Allow-Headers: Origin, Methods, Content-Type");

發現,原來是 JWT api 請求在 Header 夾帶的 Authorization 尚未設定在允許清單

在後端程式碼加上去,前端就能正常與API溝通

<?php 
  header("Access-Control-Allow-Origin: *");
  header("Access-Control-Allow-Methods: *");
  header("Access-Control-Allow-Headers: Origin, Methods, Content-Type, Authorization");

Laravel 自建 Cors Middleware 設置跨域請求

在 Laravel 5.4以前的版本

可以直接建立一個 Cors Middleware,例如:

app/Http/Middleware/Cors.php

<?php

namespace App\Http\Middleware;

use Closure;

class Cors
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        return $next($request)->header('Access-Control-Allow-Origin', '*')
                                ->header('Access-Control-Allow-Methods', '*')
                                ->header('Access-Control-Allow-Headers', 'Origin, Methods, Content-Type, Authorization')
                                ->header('Access-Control-Allow-Credentials', true);
    }
}

在 app/Http/Kernel.php 裡面的 $routeMiddleware 新增引用

        'cors' => \App\Http\Middleware\Cors::class,

就能直接在 route 裡使用,例如:

Route::group(['prefix' => $site, 'middleware' => ['cors']], function () {

但是,在 Laravel 5.5 之後的版本若按照這樣的設置流程,仍會出現問題:

Access to XMLHttpRequest at 'http://xxxx' from origin 'http://xxxxx' has been blocked by CORS policy: Response to preflight request doesn’t pass access control check: No ‘Access-Control-Allow-Origin’ header is present on the requested resource.

[ 解決方式 ]

在 app/Http/Kernel.php 裡面的 $middleware 新增引用 Cors MiddleWare 即可:

\App\Http\Middleware\Cors::class

使用 Laravel Cors 拓展

除了上面的方式,也可以使用 laravel-cors

可直接參考官方教學流程 https://github.com/barryvdh/laravel-cors

直接在 Web Server 設置跨域允許設定

在 Nginx 的 default.conf 直接設定,例如:

location ~ \.php$ {
        set $cors "true";
        add_header 'Access-Control-Allow-Origin' '*';
        add_header 'Access-Control-Allow-Methods' '*';
        add_header 'Access-Control-Allow-Headers' 'Origin, Method, Content-type, Authorization';
        add_header 'Access-Control-Allow-Credentials' 'true';
        add_header 'Allow' 'POST, GET, OPTIONS, PUT, DELETE';
        try_files $uri /index.php =404;
        fastcgi_pass php-upstream;
        fastcgi_index index.php;
        fastcgi_buffers 16 16k;
        fastcgi_buffer_size 32k;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        #fixes timeouts
        fastcgi_read_timeout 600;
        include fastcgi_params;
    }

設置完成之後,再重啟 nginx server 即可

最後提醒,如果再 Nginx 設定,就必須移除 PHP 中的 CORS

避免重複定義 HEADER 規則導致錯誤