這是我Nginx的server配置:
server {
listen 80;
server_name DataAnalysis;
location / {
if ($request_method = 'OPTIONS'){
add_header 'Access-Control-Allow-Origin' '';
add_header 'Access-Control-Allow-Methods' 'GET,POST,OPTIONS';
add_header 'Access-Control-Allow-Headers' 'Authorization,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range';
return 204;
}
if ($request_method = 'POST') {
add_header 'Access-Control-Allow-Origin' '' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' 'Authorization,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range' always;
add_header 'Access-Control-Expose-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range' always;
}
if ($request_method = 'GET') {
add_header 'Access-Control-Allow-Origin' '*' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' 'Authorization,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range' always;
add_header 'Access-Control-Expose-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range' always;
}
proxy_pass http://127.0.0.1:8080;
}
}
這裡對配置的意思是:
對於接受到的所有請求進行判斷,因為前端會傳送有許可權驗證的請求會附加Authorization請求頭,所以會出現CROS的非簡單請求。於是對於OPTIONS試探請求,由Nginx直接新增所有Access-Control的響應頭並return 204。所以所有的OPTIONS,是不會被交給我8080埠的服務的,直接由nginx處理。
而post和get請求,會由nginx轉發到8080埠進行處理,並返回響應。
碰到的問題
在我最開始的nginx配置中,我的跨域可以正常使用,但是一旦server報錯,出現500錯誤,瀏覽器會顯示跨域錯誤,這裡我並沒有深究,只是改正了server出現500的錯誤,當正常響應狀態碼為200時,瀏覽器並不會有跨域失敗的錯誤。
但是在處理帶token的許可權驗證請求時,我的設想是收到401狀態碼時跳轉回登入頁,但我發現當許可權驗證不通過,也就是返回401狀態碼時,會出現跨域錯誤問題,導致我的ajax被瀏覽器同源策略限制,無法讀取到任何error資訊,該ajax幾乎是沒有傳送的(其實已經傳送並且伺服器做出了響應,只是因為同源策略問題,被瀏覽器攔截,從而無法得到任何資訊),雖然我可以在瀏覽器控制檯清楚的看到返回了401的響應,但是因為同源策略限制,我就是無法在ajax回撥中獲取到該狀態碼。
在排查很久後才想到,之前所有非200、300的狀態碼響應,都會出現跨域報錯問題,於是開啟控制檯一看,才發現是沒有Access-Control這樣的響應頭!!!(明明出現之前跨域錯誤就應該想到的,結果折騰了這麼久才想到要去檢查響應頭!!!!!!!!!)
原因和解決辦法
原因其實很簡單,是因為在nginx轉發server響應的過程中,add_header只有在200,201,204,206,301,302,303,304,307
狀態碼時會新增,而401、500,都沒有新增。
解決:看上面的配置,在add_header最後加上always,可以讓nginx在非200、300的狀態碼後面,也使得add_header生效。