利用nginx解決跨域問題

跨域是指瀏覽器不能執行其他網站的指令碼。它是由瀏覽器的同源策略造成的,是瀏覽器對JavaScript實施的安全限制。

同源策略限制了一下行為:

Cookie、LocalStorage 和 IndexDB 無法讀取

DOM 和 JS 物件無法獲取

Ajax請求傳送不出去

那什麼是同源呢?所謂的同源是指,域名、協議、埠均為相同。出現跨域問題時,透過可以在console中看到以下錯誤。

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost/users-management/login。 (Reason: CORS header ‘Access-Control-Allow-Origin’ missing)。

以下是firefox開發者中心對該錯誤的解釋,這個解釋已經相當明確的。

The response to the CORS request is missing the required Access-Control-Allow-Origin header, which is used to determine whether or not the resource can be accessed by content operating within the current origin。

If the server is under your control, add the origin of the requesting site to the set of domains permitted access by adding it to the Access-Control-Allow-Origin header‘s value。

For example, to allow a site at https://amazing。site to access the resource using CORS, the header should be:

Access-Control-Allow-Origin: https://amazing。site

You can also configure a site to allow any site to access it by using the * wildcard。 You should only use this for public APIs。 Private APIs should never use *, and should instead have a specific domain or domains set。 In addition, the wildcard only works for requests made with the

crossorigin

attribute set to anonymous, and it prevents sending credentials like cookies in requests。

Access-Control-Allow-Origin: *

Warning:

Using the wildcard to allow all sites to access a private API is a bad idea。

To allow any site to make CORS requests without using the * wildcard (for example, to enable credentials), your server must read the value of the request's Origin header and use that value to set Access-Control-Allow-Origin, and must also set a Vary: Origin header to indicate that some headers are being set dynamically depending on the origin.

既然找到了問題所在,那麼我們就開始設定nginx配置,來增加Header “Access-Control-Allow-Origin”吧。開啟nginx的配置檔案,增加如下節點:

location ~ ^/users-management/([a-zA-Z0-9_-]+) { proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header X-Forwarded-Host $server_name; proxy_set_header Host $host; add_header ’Access-Control-Allow-Origin‘ $http_origin; add_header ’Access-Control-Allow-Credentials‘ ’true‘; add_header ’Access-Control-Allow-Methods‘ ’GET,POST,OPTIONS‘; add_header ’Access-Control-Allow-Headers‘ ’DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type‘; proxy_pass http://localhost:8081; }

以上配置的功能是將users-management相關的請求轉給後端的http://localhost:8081這個服務來處理,並在響應頭中增加以上設定的’Access-Control-Allow-Origin‘等http頭。

那麼這樣設定之後,跨域問題是否解決了呢?我們使用vue。js+axios來寫一個程式驗證一下。結果發現,users-management相關的GET請求是可以正常訪問的。但是POST請求卻還是報前面提到的跨域錯誤。為什麼POST請求會出現錯誤呢?從網路互動中可以看到,在POST通訊之前,會先axios會先發送一個OPTIONS請求來Say Hello, 所以我們還要在nginx中對OPTIONS作一些配置,允許在收到OPTIONS請求時,在響應頭中也增加 ’Access-Control-Allow-Origin‘等http頭,並且順便告訴客戶端不要每次傳送POST請求時都先發送OPTIONS請求了。

具體設定如下:

location ~ ^/users-management/([a-zA-Z0-9_-]+) { if ($request_method = ’OPTIONS‘) { add_header ’Access-Control-Allow-Origin‘ ’*‘; add_header ’Access-Control-Allow-Methods‘ ’GET, POST, OPTIONS‘; # # Custom headers and headers various browsers *should* be OK with but aren’t # add_header ‘Access-Control-Allow-Headers’ ‘DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type’; # # Tell client that this pre-flight info is valid for 20 days # add_header ‘Access-Control-Max-Age’ 1728000; add_header ‘Content-Type’ ‘text/plain charset=UTF-8’; add_header ‘Content-Length’ 0; return 204; } proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header X-Forwarded-Host $server_name; proxy_set_header Host $host; add_header ‘Access-Control-Allow-Origin’ $http_origin; add_header ‘Access-Control-Allow-Credentials’ ‘true’; add_header ‘Access-Control-Allow-Methods’ ‘GET,POST,OPTIONS’; add_header ‘Access-Control-Allow-Headers’ ‘DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type’; proxy_pass http://localhost:8081; }

設定完成之後,你會發現可以透過axios來正常呼叫POST請求了。