前言
提示:本人在生產(chǎn)部署服務(wù)時(shí)遇到一系列跨域問題和https配置問題,特此做以下記錄:
前言一、什么是跨域?
跨域是指a頁面想獲取b頁面資源,如果a、b頁面的協(xié)議、域名、端口、子域名不同,或是a頁面為ip地址,b頁面為域名地址,所進(jìn)行的訪問行動都是跨域的,而瀏覽器為了安全問題一般都限制了跨域訪問,也就是不允許跨域請求資源。
前言二、跨域產(chǎn)生的條件?
注意:跨域限制訪問,其實(shí)是瀏覽器的限制。理解這一點(diǎn)很重要。所以,當(dāng)用java(或者其他語言)調(diào)用RESTful api,從來不會報(bào)什么跨域錯(cuò)誤
跨域處理常用的兩種辦法
一、springboot如何處理跨域問題?
1.1 controller中單獨(dú)配置
每個(gè)Controller控制器的類上都添加@CrossOrigin跨域注解
1.2 在@configation類中全局配置
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**") // 匹配了所有的URL
.allowedHeaders("*") // 允許跨域請求包含任意的頭信息
.allowedMethods("*") // 設(shè)置允許的方法
.allowedOrigins("*") // 設(shè)置允許跨域請求的域名
.allowCredentials(true); // 是否允許證書,默認(rèn)false
}
}
1.3在過濾器中添加響應(yīng)頭
protected void doFilter(HttpServletRequest req, HttpServletResponse res, FilterChain chain) throws IOException, ServletException {
res.addHeader("Access-Control-Allow-Origin", req.getHeader("Origin"));
res.addHeader("Access-Control-Allow-Methods", "*");
res.addHeader("Access-Control-Allow-Headers", "Accept,Authorization,DNT,Content-Type,Referer,User-Agent");
res.addHeader("Access-Control-Allow-Credentials","true"); // 允許攜帶驗(yàn)證信息
chain.doFilter(req, res);
}
二、nginx如何處理跨域問題?
2.1 給Nginx服務(wù)器配置響應(yīng)的header參數(shù)
當(dāng)出現(xiàn)403跨域錯(cuò)誤的時(shí)候 No ‘Access-Control-Allow-Origin’ header is present on the requested resource,需要給Nginx服務(wù)器配置響應(yīng)的header參數(shù)。
location / {
add_header Access-Control-Allow-Origin *; //允許所有請求訪問
add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS'; //允許訪問的請求類型
add_header Access-Control-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';
//預(yù)檢請求需要用到
if ($request_method = 'OPTIONS') {
return 204;
}
}
2.2、各參數(shù)詳細(xì)解讀
- Access-Control-Allow-Origin
服務(wù)器默認(rèn)是不被允許跨域的,給Nginx服務(wù)器配置`Access-Control-Allow-Origin *`后,表示服務(wù)器可以接受所有的請求源(Origin),即接受所有跨域的請求。
- Access-Control-Allow-Headers 是為了防止出現(xiàn)以下錯(cuò)誤:
Request header field Content-Type is not allowed by Access-Control-Allow-Headers in preflight response.
這個(gè)錯(cuò)誤表示當(dāng)前請求Content-Type的值不被支持。其實(shí)是我們發(fā)起了"application/json"的類型請求導(dǎo)致的。這里涉及到一個(gè)概念:預(yù)檢請求(preflight request),請看下面"預(yù)檢請求"的介紹。
-
Access-Control-Allow-Methods 是為了防止出現(xiàn)以下錯(cuò)誤:
Content-Type is not allowed by Access-Control-Allow-Headers in preflight response. -
給OPTIONS 添加 204的返回,是為了處理在發(fā)送POST請求時(shí)Nginx依然拒絕訪問的錯(cuò)誤
發(fā)送"預(yù)檢請求"時(shí),需要用到方法 OPTIONS ,所以服務(wù)器需要允許該方法。
Nginx配置域名跨域多個(gè)域名
方法一:使用nginx內(nèi)置變量(常用)
server {
set $cors '';
if ($http_origin ~* "^http://deomain01:port$") {
set $cors $http_origin;
}
if ($http_origin ~* "^http://deomain02:port$") {
set $cors $http_origin;
}
if ($http_origin ~* "^http://deomain002:port$") {
set $cors $http_origin;
}
location /live{
...
add_header 'Access-Control-Allow-Origin' '$cors';
add_header 'Access-Control-Allow-Credentials' 'true';
# 為預(yù)檢請求加的header
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE';
#為預(yù)檢請求加的header
add_header 'Access-Control-Allow-Headers' '*';
}
解釋:$http_origin這個(gè)格式是nginx取請求中header的XXX的值的。
這里取的是origin,而一般跨域請求都會將請求的來源放在origin中(瀏覽器會往跨域請求的header上面加origin這個(gè)header)
$ cors 變量獲取想要的跨域域名并賦值到 “add_header ‘Access-Control-Allow-Origin’ ‘$cors’”中。
方法二:使用map
map $http_origin $cors_list{
default http://aaa.cn;
"~ http://bbb.cn" http://bbb.cn;
}
server {
listen 8089;
server_name localhost;
location /live{
...
add_header 'Access-Control-Allow-Origin' '$cors_list';
add_header 'Access-Control-Allow-Credentials' 'true';
# 為預(yù)檢請求加的header
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE';
#為預(yù)檢請求加的header
add_header 'Access-Control-Allow-Headers' '*';
}
解釋:
map指令是ngx_http_map_module模塊提供的,默認(rèn)情況下nginx有加載這個(gè)模塊。
語法: map $var1 $var2 {…}
默認(rèn)值: -
配置段: http
map為一個(gè)變量設(shè)置的映射表。映射表由兩列組成,匹配模式和對應(yīng)的值。
在map塊里的參數(shù)指定了源變量值和結(jié)果值的對應(yīng)關(guān)系。
default: 沒有匹配結(jié)果將使用的默認(rèn)值。如果沒有設(shè)置default,將會用一個(gè)空的字符串作為默認(rèn)的結(jié)果。
匹配模式可以是一個(gè)簡單的字符串或者正則表達(dá)式,使用正則表達(dá)式要用(‘~’)。
方法三:正則匹配三級域名
location / {
if ($http_origin ~* (http?://.*\.aliuncle\.top$)) {
add_header Access-Control-Allow-Origin $http_origin;
}
index index.php;
try_files $uri $uri/ /index.php?$args;
}
注意:在nginx.conf配置文件配置跨域時(shí),記得清除客戶端如瀏覽器緩存,否則會出現(xiàn)配置沒生效的情況。
2.3、 nginx處理跨域過程這種遇到的各種報(bào)錯(cuò)處理
1、跨域請求無法攜帶身份憑證cookie報(bào)錯(cuò)()
問題描述:請求中無論如何都無法傳遞身份憑證cookie
解決:
前端:
1、在前端請求的時(shí)候設(shè)置 request 對象的屬性 withCredentials 為 true;
2、后端支持響應(yīng)頭Credentials 為 true注意:除了 Access-Control-Allow-Credentials 之外,跨域發(fā)送 Cookie 還要求 Access-Control-Allow-Origin 不允許使用通配符。 事實(shí)上不僅不允許通配符,而且 只能指定單一域名:
否則會報(bào)一下cros錯(cuò)誤
2.4、 預(yù)檢請求(preflight request)報(bào)錯(cuò)
介紹:
跨域資源共享(CORS)標(biāo)準(zhǔn)新增了一組 HTTP 首部字段,允許服務(wù)器聲明哪些源站有權(quán)限訪問哪些資源。另外,規(guī)范要求,對那些可能對服務(wù)器數(shù)據(jù)產(chǎn)生副作用的HTTP 請求方法(特別是 GET 以外的 HTTP 請求,或者搭配某些 MIME 類型的 POST 請求),瀏覽器必須首先使用 OPTIONS 方法發(fā)起一個(gè)預(yù)檢請求(preflight request),從而獲知服務(wù)端是否允許該跨域請求。服務(wù)器確認(rèn)允許之后,才發(fā)起實(shí)際的 HTTP 請求。在預(yù)檢請求的返回中,服務(wù)器端也可以通知客戶端,是否需要攜帶身份憑證(包括 Cookies 和 HTTP 認(rèn)證相關(guān)數(shù)據(jù))。
其實(shí)Content-Type字段的類型為application/json的請求就是上面所說的搭配某些 MIME 類型的 POST 請求,CORS規(guī)定,Content-Type不屬于以下MIME類型的,都屬于預(yù)檢請求:
application/x-www-form-urlencoded
multipart/form-data
text/plain
2.4.1、預(yù)期請求流程(先發(fā)送options請求/響應(yīng),再發(fā)送post請求)
2.4.2、預(yù)檢請求報(bào)錯(cuò)
Request header field Content-Type is not allowed by Access-Control-Allow-Headers in preflight response.
解釋:
application/json的請求 會在正式通信之前,增加一次"預(yù)檢"請求,這次"預(yù)檢"請求會帶上頭部信息,服務(wù)器回應(yīng)時(shí),返回的頭部信息如果不包含Access-Control-Allow-Headers: Content-Type則表示不接受非默認(rèn)的的Content-Type。即出現(xiàn)以上錯(cuò)誤:
預(yù)檢請求頭信息
Access-Control-Request-Headers: Content-Type:
OPTIONS /api/test HTTP/1.1
Origin: http://foo.example
Access-Control-Request-Method: POST
Access-Control-Request-Headers: Content-Type
2.4.3、預(yù)檢請求報(bào)錯(cuò)如何解決?
前面也提到了預(yù)檢請求,我們只需要在nginx代理之前添加我們的判斷就可以讓nginx在遇到options請求時(shí)返回處理成功狀態(tài)碼
//預(yù)檢請求需要用到
if ($request_method = 'OPTIONS') {
return 204;
}
nginx狀態(tài)碼詳解
http詳解
2.4.4 Access-Control-Allow-Origin只能被設(shè)置一次,在后端配置后,就不能在nginx再次配置
報(bào)如下錯(cuò)誤:
解釋:服務(wù)器返回的 Access-Control-Allow-Origin 值不應(yīng)該是一個(gè)列表,因?yàn)闉g覽器只會接受一個(gè)值,并且不能為空。
2.5、請求頭額外攜帶了信息例如攜帶了Authorization
報(bào)錯(cuò):(Request header field authorization is not allowed by Access-Control-Allow-Headers in preflight)
2.5.1 、解釋
響應(yīng)首部 Access-Control-Allow-Headers 用于 preflight request (預(yù)檢請求)中,列出了將會在正式請求的 Access-Control-Request-Headers 字段中出現(xiàn)的首部信息。簡單首部,如 simple headers、Accept、Accept-Language、Content-Language、Content-Type (只限于解析后的值為 application/x-www-form-urlencoded、multipart/form-data 或 text/plain 三種MIME類型(不包括參數(shù))),它們始終是被支持的,不需要在這個(gè)首部特意列出。
像Authorization,x-token等額外的請求頭信息就需要被允許,此報(bào)錯(cuò)通過請求預(yù)處理得知請求頭Authorization不被允許,就報(bào)了跨域
2.5.2、解決
需要加入允許的頭部Authorization,并且判斷請求的方法是options的時(shí)候,返回ok(200)給客戶端,這樣才能繼續(xù)發(fā)正式的post請求。
add_header 'Access-Control-Allow-Origin' '*' always;
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Methods' 'GET, POST, PATCH, DELETE, PUT, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type, X-Custom-Header, Access-Control-Expose-Headers, Token, Authorization';
add_header 'Access-Control-Allow-Headers' '*';
add_header 'Access-Control-Max-Age' 1728000;
2.6、 谷歌新版本跨域錯(cuò)誤深度剖析與解決:request client is not a secure context and the resource is in more-private address
2.6.1 報(bào)錯(cuò)原因
報(bào)錯(cuò):不安全的請求方請求了更私有的本地資源
原因:從谷歌94版本開始,谷歌針對不安全網(wǎng)站訪問私有網(wǎng)絡(luò)進(jìn)行了更新,阻止這種訪問更私有資源的請求。同時(shí),在進(jìn)行私有網(wǎng)絡(luò)資源請求前,還會先發(fā)送OPTIONS預(yù)檢請求。
2.6.2 解決辦法
1、更換非谷歌內(nèi)核瀏覽器(使用火狐,edge等)或者降低版本
2、修改谷歌瀏覽器設(shè)置
解決:禁用設(shè)置,對于谷歌瀏覽器版本在94~101之間的,可以通過修改瀏覽器設(shè)置來使得http網(wǎng)站發(fā)出的對私有資源的請求可以成功發(fā)送。
步驟如下:
步驟一:在瀏覽器輸入:chrome://flags/#block-insecure-private-network-requests
步驟二 :將Block insecure private network requests.項(xiàng)的Default改為Disabled,重啟瀏覽器即可(不同版本配置不同具體可參考下述參考鏈接)
參考連接
3、修改內(nèi)網(wǎng)圖片等資源的訪問方式,全部采用https方式訪問即可從根本上解決問題
https 如何配置(nginx中配置ssl)
一、配置
總結(jié)下來幾個(gè)步驟:申請ssl->ssl文件存儲到服務(wù)器->nginx配置ssl
server {
listen 8002 ssl;
server_name temp.3zyun.com ; #公網(wǎng)ip 115.148.208.122
client_max_body_size 1024M;
ssl_certificate /usr/local/nginx/yjssl/7604469_temp.3zyun.com_nginx/7604469_temp.3zyun.com.pem;
ssl_certificate_key /usr/local/nginx/yjssl/7604469_temp.3zyun.com_nginx/7604469_temp.3zyun.com.key;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on ;
location / {
proxy_pass http://bpm-server/;
proxy_set_header Host $host:$server_port;
}
}
注意 :端口后面要加上ssl才可生效
ssl配置靈感來源于此文章
二、遇到的一系列問題
2.1、h5項(xiàng)目打包部署到生產(chǎn)
Mixed Content: The page at ‘xxx’ was loaded over HTTPS, but requested an insecure resource ‘xxx’. This request has been blocked; the content must be served over HTTPS問題解決
解釋:當(dāng)我們的瀏覽器出現(xiàn)類似“was loaded over HTTPS, but requested an insecure resource/frame”這種錯(cuò)誤是,一般都是因?yàn)槲覀兊木W(wǎng)站是HTTPS的,而對方的鏈接是HTTP協(xié)議的,因此在Ajax或者javascript請求時(shí),就會報(bào)如上這種錯(cuò)誤,查在https中請求http接口或引入http資源都會被直接blocked(阻止),瀏覽器默認(rèn)此行為不安全,會攔截。
解決辦法:
(在index.html的head中加入以下代碼)
<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests" />
作用:加入該標(biāo)簽的原理是使用META標(biāo)簽強(qiáng)制將http請求轉(zhuǎn)成https(SSL協(xié)議)請求。文章來源:http://www.zghlxwxcb.cn/news/detail-784456.html
總結(jié)
總是在不斷踩坑后成長?。?!文章來源地址http://www.zghlxwxcb.cn/news/detail-784456.html
到了這里,關(guān)于nginx處理cros跨域遇到的各種問題及解決方案,以及https配置和瀏覽器https不安全問題處理的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!