在前端領域中,跨域是指瀏覽器允許向服務器發送跨域請求,從而克服Ajax只能同源使用的限制。
一般根據錯誤來定位是否是跨域問題,報錯如下:
或者:
1.2 常見的跨域場景
URL |
說明 |
是否允許通信 |
http://www.domain.com/a.js |
同一域名,不同文件或路徑 |
允許 |
同一域名,不同端口 |
不允許 |
|
http://www.domain.com/a.js |
同一域名,不同協議 |
不允許 |
http://www.domain.com/a.js |
域名和域名對應相同ip |
不允許 |
http://www.domain.com/a.js |
主域相同,子域不同 |
不允許 |
http://www.domain1.com/a.js |
不同域名 |
不允許 |
1.3 如何解決跨域問題?
目前我了解的解決跨域的幾種方式:手寫過濾器,手寫攔截器,jsonnp,注解方式,配置nginx反向代理,共五種解決方式。
我們通常采用修改nginx配置文件來解決跨域問題
1.3.1 nginx代理跨域
nginx代理跨域,實質和CORS跨域原理一樣,通過配置文件設置請求響應頭Access-Control-Allow-Origin…等字段。
1) nginx配置解決iconfont跨域
瀏覽器跨域訪問js、css、img等常規靜態資源被同源策略許可,但iconfont字體文件(eot|otf|ttf|woff|svg)例外,此時可在nginx的靜態資源服務器中加入以下配置。
2) nginx反向代理接口跨域
跨域問題:同源策略僅是針對瀏覽器的安全策略。服務器端調用HTTP接口只是使用HTTP協議,不需要同源策略,也就不存在跨域問題。
實現思路:通過Nginx配置一個代理服務器域名與domain1相同,端口不同)做跳板機,反向代理訪問domain2接口,並且可以順便修改cookie中domain信息,方便當前域cookie寫入,實現跨域訪問。
nginx具體配置:
server {
listen 8888;
server_name test.demo.com;
location / {
proxy_pass http://120.147.88.27:8888;
add_header Access-Control-Allow-Origin *;
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range,Authorization,Accept,DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
#add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization,Accept';
add_header 'Access-Control-Allow-Headers' '*';
}
}
詳細解釋:
add_header Access-Control-Allow-Methods *;
add_header Access-Control-Allow-Origin $http_origin;
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,web-token,app-token,Authorization,Accept,Origin,Keep-Alive,User-Agent,X-Mx-ReqToken,X-Data-Type,X-Auth-Token,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain; charset=utf-8';
add_header 'Content-Length' 0;
return 204;
}
1、Access-Control-Allow-Origin,這里使用變量 $http_origin取得當前來源域,大家說用“*”代表允許所有,我實際使用並不成功,原因未知;
2、Access-Control-Allow-Credentials,為 true 的時候指請求時可帶上Cookie,自己按情況配置吧;
3、Access-Control-Allow-Methods,OPTIONS一定要有的,另外一般也就GET和POST,如果你有其它的也可加進去;
4、Access-Control-Allow-Headers,這個要注意,里面一定要包含自定義的http頭字段(就是說前端請求接口時,如果在http頭里加了自定義的字段,這里配置一定要寫上相應的字段),從上面可看到我寫的比較長,我在網上搜索一些常用的寫進去了,里面有“web-token”和“app-token”,這個是我項目里前端請求時設置的,所以我在這里要寫上;
5、Access-Control-Expose-Headers,可不設置,看網上大致意思是默認只能獲返回頭的6個基本字段,要獲取其它額外的,先在這設置才能獲取它;
6、語句“ if ($request_method = 'OPTIONS') { ”,因為瀏覽器判斷是否允許跨域時會先往后端發一個 options 請求,然后根據返回的結果判斷是否允許跨域請求,所以這里單獨判斷這個請求,然后直接返回;
# 指定允許跨域的方法,*代表所有
add_header Access-Control-Allow-Methods *;
# 預檢命令的緩存,如果不緩存每次會發送兩次請求
add_header Access-Control-Max-Age 3600;
# 帶cookie請求需要加上這個字段,並設置為true
add_header Access-Control-Allow-Credentials true;
# 表示允許這個域跨域調用(客戶端發送請求的域名和端口)
# $http_origin動態獲取請求客戶端請求的域 不用*的原因是帶cookie的請求不支持*號
add_header Access-Control-Allow-Origin $http_origin;
# 表示請求頭的字段 動態獲取
add_header Access-Control-Allow-Headers $http_access_control_request_headers;
1.4 問題1:配置跨域不生效
1)使用nginx -V進行查看是否存在header模塊,如沒有則進行重新編譯安裝nginx
2)下載這兩個模塊編譯即可
headers-more-nginx-module-master.zip
nginx-upload-module-2.2.zip
1.5 問題2: nginx會去掉帶有下划線的Header鍵值
原因:nginx對header name的字符做了限制,默認 underscores_in_headers 為off,表示如果 header name中包含下划線,則忽略掉,部署后就獲取不到。
解決:在header里不要用 “_” 下划線,可以用駝峰命名或者其他的符號(如減號-)代替。nginx默認忽略掉下划線可能有些原因。
在nginx里的 nginx.conf文件中配置http的部分添加 : underscores_in_headers on;(默認值是off)