一文搞懂跨域的所有問題

目前很多應(yīng)用開發(fā)都是多客戶端的峻厚,前端調(diào)用后端提供的 API 來獲取數(shù)據(jù)杆烁,很多都是前后端分離的架構(gòu),但這樣相比之前的單應(yīng)用系統(tǒng)會帶來跨域的問題癣丧。

本文配套的代碼地址:https://github.com/weizhiwen/cross-domain

img

0捍壤、什么是跨域問題

前端調(diào)用的后端接口不屬于同一個(gè)域(域名或端口不同)骤视,就會產(chǎn)生跨域問題,也就是說你的應(yīng)用訪問了該應(yīng)用域名或端口之外的域名或端口鹃觉。

img

1专酗、為什么會發(fā)生跨域問題

要同時(shí)滿足三個(gè)條件才會產(chǎn)生跨域問題,這也就是為什么會產(chǎn)生跨域的原因盗扇。

  • 1祷肯、瀏覽器限制,而不是服務(wù)端限制疗隶,可以查看Network佑笋,請求能夠正確響應(yīng),response返回的值也是正確的
  • 2斑鼻、請求地址的域名或端口和當(dāng)前訪問的域名或端口不一樣
  • 3蒋纬、發(fā)送的是XHR(XMLHttpRequest)請求,可以使用 a 標(biāo)簽(模擬xhr請求)和 img 標(biāo)簽(模擬json請求)做對比(控制臺只報(bào)了一個(gè)跨域異常)
img

關(guān)于 XMLHTTPRequest 可以參看這篇文章 《你真的會使用XMLHttpRequest嗎卵沉?》

2、解決跨域問題的三種思路

  • 1法牲、客戶端瀏覽器解除跨域限制(理論上可以但是不現(xiàn)實(shí))
  • 2史汗、發(fā)送JSONP請求替代XHR請求(并不能適用所有的請求方式,不推薦)
  • 3拒垃、修改服務(wù)器端(包括HTTP服務(wù)器和應(yīng)用服務(wù)器)(推薦

2.1 客戶端瀏覽器解除跨域限制

瀏覽器默認(rèn)都是開啟跨域安全檢查的停撞,我們可以使用命令行啟動(dòng)瀏覽器,加上禁止安全檢查的參數(shù),以谷歌瀏覽器為例戈毒,chrome.exe --disable-web-security --user-data-dir=E:/temp --user-data-dir 為瀏覽器緩存臨時(shí)目錄艰猬,瀏覽器這時(shí)會提示安全問題。

img

2.1.1 瀏覽器如何判斷一個(gè)請求是不是跨域請求埋市?

瀏覽器會根據(jù)同源策略來判斷一個(gè)請求是不是跨域請求冠桃。

非跨域請求,在請求頭中會只包含請求的主機(jī)名道宅。

img

跨域請求食听,在請求頭中會既包含要請求的主機(jī)名還包括當(dāng)前的源主機(jī)名,如果這兩者不一致污茵,那就是跨域請求了樱报。

img

2.1.2 瀏覽器對請求的分類

在HTTP1.1 協(xié)議中的,請求方法分為GET泞当、POST迹蛤、PUT、DELETE襟士、HEAD盗飒、TRACE、OPTIONS敌蜂、CONNECT 八種箩兽。瀏覽器根據(jù)這些請求方法和請求類型將請求劃分為簡單請求和非簡單請求。

簡單請求:瀏覽器先發(fā)送(執(zhí)行)請求然后再判斷是否跨域章喉。

請求方法為 GET汗贫、POST、HEAD秸脱,請求頭header中無自定義的請求頭信息落包,請求類型Content-Type 為 text/plain、multipart/form-data摊唇、application/x-www-form-urlencoded 的請求都是簡單請求咐蝇。

非簡單請求:瀏覽器先發(fā)送預(yù)檢命令(OPTIONS方法),檢查通過后才發(fā)送真正的數(shù)據(jù)請求巷查。

{% asset_img 非簡單請求的預(yù)檢命令.png 非簡單請求的預(yù)檢命令%}

預(yù)檢命令會發(fā)送自定義頭為Access-Control-Request-Headers: content-type的請求到服務(wù)器有序,根據(jù)響應(yīng)頭的中的 “Access-Control-Allow-Headers”: “Content-Type” 判斷服務(wù)器是否允許跨域訪問。預(yù)檢命令是可以緩存岛请,服務(wù)器端設(shè)置 “Access-Control-Max-Age”: “3600”旭寿,這樣后面發(fā)送同樣的跨域請求就不需要先發(fā)送預(yù)檢命令了。

請求方法為 PUT崇败、DELETE 的 AJAX 請求盅称、發(fā)送 JSON 格式的 AJAX 請求肩祥、帶自定義頭的 AJAX 請求都是非簡單請求。

2.2 發(fā)送JSONP請求替代XHR請求

2.2.1 JSONP 是什么

JSONP(JSON with Padding)是JSON的一種補(bǔ)充使用方式缩膝,不是官方協(xié)議混狠,而是利用 Script 標(biāo)簽請求資源可以跨域的特點(diǎn),來解決跨域問題的疾层,是一種變通的解決方案将饺。

2.2.2 使用 JSONP,服務(wù)器后臺需要改動(dòng)嗎云芦?

答案是需要俯逾,這里以Spring Boot為例,在 Spring Boot 1.5 大版本中舅逸,添加一個(gè)切面來支持JSONP請求桌肴,注意在 Spring Boot 2.x 大版本中已經(jīng)廢棄了 AbstractJsonpResponseBodyAdvice 類,不推薦這種方式解決跨域問題琉历。

AJAX代碼如下:

$.ajax({
    url: baseUrl + "/get1",
    dataType: "jsonp", // 關(guān)鍵字段
    jsonp: "callback", // 前后端默認(rèn)的約定
    cache: true, // 表示請求結(jié)果可以被緩存坠七,url中不會有下劃線參數(shù)了
    success: function(json) {
        result = json;
    }
});

服務(wù)端代碼:

@ControllerAdvice
public class JsonpAdvice extends AbstractJsonpResponseBodyAdvice {
    public JsonpAdvice() {
        super("callback");
    }
}

2.2.3 JSONP 實(shí)現(xiàn)原理

JSONP請求的類型是JavaScript腳本(callback 作為前后端的約定,callback的值做為方法名旗笔,json內(nèi)容作為方法的參數(shù))彪置,而XHR請求的類型是json類型。

img

可以在瀏覽器中查看 Jquery 源碼來驗(yàn)證 JSONP 是否將請求包裝成了 script 腳本蝇恶。

img

在 Jquery 源碼中打斷點(diǎn)拳魁。

img

刷新后查看 element 元素,可以看到 Jquery 在 html 源碼中添加了 script 標(biāo)簽撮弧。

img

2.2.4 JSONP 的缺點(diǎn)

1潘懊、只支持 GET 方法請求,不管 AJAX 中實(shí)際的請求方法是不是 GET

2贿衍、服務(wù)端還需要修改代碼

3授舟、發(fā)送的不是 XHR 請求,無法使用 XHR 對象(但這也是為什么可以解決跨域問題的根本)

總之贸辈,并不推薦使用 JSONP 方式來解決跨域問題释树,因?yàn)檫€有更好的解決方式。

2.3 修改服務(wù)器端

根據(jù)現(xiàn)如今網(wǎng)站架構(gòu)設(shè)計(jì)擎淤,可以將前端應(yīng)用看作調(diào)用方使用服務(wù)奢啥,將后端應(yīng)用看作被調(diào)用方提供服務(wù)。

img

根據(jù)服務(wù)器的作用嘴拢,可以將服務(wù)器分為 HTTP 服務(wù)器和應(yīng)用服務(wù)器桩盲,所有修改服務(wù)器端既可以是修改應(yīng)用服務(wù)器,也可以是修改 HTTP 服務(wù)器炊汤。

2.3.1 被調(diào)用方修改

被調(diào)用方的解決思路是在響應(yīng)頭中增加指定的字段允許調(diào)用方服務(wù)器跨域調(diào)用正驻。

img

在應(yīng)用服務(wù)器增加指定字段

對于不帶 Cookie 的跨域請求,設(shè)置允許跨域的原始域名為任意域名抢腐,“Access-Control-Allow-Origin”: “”姑曙,設(shè)置允許跨域的方法為任意方法,“Access-Control-Allow-Methods”: “”迈倍,但是這樣的星號設(shè)置不能滿足帶 Cookie 的跨域請求伤靠。

img

對于帶 Cookie 的跨域請求,要指名允許跨域請求的調(diào)用方主機(jī)名啼染,Cookie 要加在調(diào)用方宴合。

帶自定義頭的跨域請求,設(shè)置允許跨域的請求頭自定義的請求頭迹鹅,“Access-Control-Allow-Headers”:“自定義的請求頭”卦洽。

在 Java Web 中,可以添加一個(gè)過濾器來設(shè)置上面的參數(shù)斜棚。

img

而使用 Spring Boot 框架阀蒂,只需要在 Controller 類上加上 @CrossOrigin 注解就可以輕松解決跨域問題了。

在 HTTP 服務(wù)器增加指定字段

以常用的 Nginx 服務(wù)器和 Apache 服務(wù)器為例弟蚀。

Nginx 服務(wù)器允許跨域配置(注意不要手動(dòng)直接點(diǎn)擊Nginx.exe蚤霞,否則停止和重新載入配置會失敗的):

img

Apache 服務(wù)器允許跨域配置:

img

2.3.2 調(diào)用方修改

調(diào)用方的解決思路是反向代理,也即是將被調(diào)用方的域名代理到調(diào)用方域名下义钉,這樣就符合同源策略了昧绣,也就解決了跨域問題。

img

調(diào)用方修改一般都是直接修改 HTTP 服務(wù)器配置捶闸。

Nginx 服務(wù)器反向代理配置:

img

Apache 服務(wù)器反向代理配置:

img
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末夜畴,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子鉴嗤,更是在濱河造成了極大的恐慌斩启,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,919評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件醉锅,死亡現(xiàn)場離奇詭異兔簇,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)硬耍,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,567評論 3 392
  • 文/潘曉璐 我一進(jìn)店門垄琐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人经柴,你說我怎么就攤上這事狸窘。” “怎么了坯认?”我有些...
    開封第一講書人閱讀 163,316評論 0 353
  • 文/不壞的土叔 我叫張陵翻擒,是天一觀的道長氓涣。 經(jīng)常有香客問我,道長陋气,這世上最難降的妖魔是什么劳吠? 我笑而不...
    開封第一講書人閱讀 58,294評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮巩趁,結(jié)果婚禮上痒玩,老公的妹妹穿的比我還像新娘。我一直安慰自己议慰,他們只是感情好蠢古,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,318評論 6 390
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著别凹,像睡著了一般草讶。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上炉菲,一...
    開封第一講書人閱讀 51,245評論 1 299
  • 那天到涂,我揣著相機(jī)與錄音,去河邊找鬼颁督。 笑死践啄,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的沉御。 我是一名探鬼主播屿讽,決...
    沈念sama閱讀 40,120評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼吠裆!你這毒婦竟也來了伐谈?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,964評論 0 275
  • 序言:老撾萬榮一對情侶失蹤试疙,失蹤者是張志新(化名)和其女友劉穎诵棵,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體祝旷,經(jīng)...
    沈念sama閱讀 45,376評論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡履澳,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,592評論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了怀跛。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片距贷。...
    茶點(diǎn)故事閱讀 39,764評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖吻谋,靈堂內(nèi)的尸體忽然破棺而出忠蝗,到底是詐尸還是另有隱情,我是刑警寧澤漓拾,帶...
    沈念sama閱讀 35,460評論 5 344
  • 正文 年R本政府宣布阁最,位于F島的核電站戒祠,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏速种。R本人自食惡果不足惜得哆,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,070評論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望哟旗。 院中可真熱鬧,春花似錦栋操、人聲如沸纠脾。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,697評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至详羡,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間宿饱,已是汗流浹背陨溅。 一陣腳步聲響...
    開封第一講書人閱讀 32,846評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留葱绒,地道東北人感帅。 一個(gè)月前我還...
    沈念sama閱讀 47,819評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像地淀,于是被迫代替她去往敵國和親失球。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,665評論 2 354

推薦閱讀更多精彩內(nèi)容