前端跨域問題及解決辦法

1娜氏、什么是跨域抽活?

瀏覽器遵循同源政策(scheme(協(xié)議)子巾、host(主機)和port(端口)都相同則為同源)。

非同源站點有這樣一些限制:

a茶敏、不能讀取和修改對方的 DOM

b壤靶、不讀訪問對方的 Cookie、IndexDB 和 LocalStorage

c惊搏、限制 XMLHttpRequest 請求贮乳,AJAX 請求不能發(fā)送忧换。

當瀏覽器向目標 URI 發(fā) Ajax 請求時,只要當前 URL 和目標 URL 不同源向拆,則產生跨域亚茬,被稱為跨域請求。跨域請求的響應一般會被瀏覽器所攔截浓恳,注意才写,是被瀏覽器攔截,響應其實是成功到達客戶端了奖蔓。

2、跨域的解決方案

1)CORS

CORS 跨域資源共享(Cross-origin resource sharing)其實是 W3C 的一個標準讹堤,全稱是跨域資源共享吆鹤。它需要瀏覽器和服務器的共同支持。支持所有類型的HTTP請求洲守。

1)若瀏覽器發(fā)送的是個跨域請求疑务,http請求中就會攜帶一個名為Origin的頭表明自己的“位置”,如Origin: http://localhost:5432

2)服務端接到請求后梗醇,就可以根據傳過來的Origin頭做邏輯知允,決定是否要將資源共享給這個源嘍。而這個決定通過響應頭Access-Control-Allow-Origin來承載叙谨,它的value值可以是任意值温鸽,有如下情況:

a、值為*手负,通配符涤垫,允許所有的Origin共享此資源。

b竟终、值為http://localhost:5432(也就是和Origin相同)蝠猬,共享給此Origin。

c统捶、值為非http://localhost:5432(也就是和Origin不相同)榆芦,不共享給此Origin。

d喘鸟、無此頭:不共享給此origin匆绣;有此頭:值有如下可能情況。

3)瀏覽器接收到Response響應后什黑,會去提取Access-Control-Allow-Origin這個頭犬绒。然后根據上述規(guī)則來決定要接收此響應內容還是拒絕

我們需要清楚兩個概念:?簡單請求非簡單請求。瀏覽器根據請求方法和請求頭的特定字段兑凿,將請求做了一下分類凯力,具體來說規(guī)則是這樣茵瘾,凡是滿足下面條件的屬于簡單請求:

a、請求方法為 GET咐鹤、POST 或者 HEAD

b拗秘、請求頭的取值范圍: Accept、Accept-Language祈惶、Content-Language雕旨、Content-Type(只限于三個值application/x-www-form-urlencoded、multipart/form-data捧请、text/plain)凡涩。

剩下的則是非簡單請求。

簡單請求會自動在請求頭當中疹蛉,添加一個Origin字段活箕,用來說明請求來自哪個源。服務器拿到請求之后可款,在回應時對應地添加Access-Control-Allow-Origin字段育韩,如果Origin不在這個字段的范圍中,那么瀏覽器就會將響應攔截闺鲸。

Access-Control-Allow-Origin字段是服務器用來決定瀏覽器是否攔截這個響應筋讨,這是必需的字段。

Access-Control-Allow-Credentials表示是否允許發(fā)送 Cookie摸恍,對于跨域請求悉罕,瀏覽器對這個字段默認值設為 false,而如果需要拿到瀏覽器的 Cookie立镶,需要添加這個響應頭并設為true, 并且在前端也需要設置withCredentials屬性:

Access-Control-Expose-Headers:可選

CORS請求時蛮粮,XMLHttpRequest對象的getResponseHeader()方法只能拿到6個基本字段:Cache-Control、Content-Language谜慌、Content-Type然想、Expires、Last-Modified欣范、Pragma变泄。如果想拿到其他字段,就必須在Access-Control-Expose-Headers里面指定恼琼。

非簡單請求

非簡單請求體現(xiàn)在兩個方面:?預檢請求和響應字段妨蛹。

我們以 PUT 方法為例

當這段代碼執(zhí)行后,非簡單請求的CORS請求晴竞,會在正式通信之前蛙卤,增加一次HTTP查詢請求稱為預檢請求。這個預檢請求的請求行和請求體是下面這個格式:

預檢請求的方法是OPTIONS颤难,同時會加上Origin源地址和Host目標地址神年,同時也會加上Access-Control-Request-Method(列出 CORS 請求用到哪個HTTP方法)、Access-Control-Request-Headers(指定 CORS 請求將要加上什么請求頭)行嗤。

接下來是響應字段已日,響應字段也分為兩部分,一部分是對于預檢請求的響應栅屏,一部分是對于?CORS 請求的響應飘千。

預檢請求的響應。如下面的格式:

其中有這樣幾個關鍵的響應頭字段:

a栈雳、Access-Control-Allow-Origin: 必選护奈,表示可以允許請求的源,可以填具體的源名哥纫,也可以填*表示允許任意源請求霉旗。

b、Access-Control-Allow-Methods: 表示允許的請求方法列表磺箕。

c、Access-Control-Allow-Credentials: 它的值是一個布爾值抛虫,表示是否允許發(fā)送Cookie松靡。默認情況下,Cookie不包括在CORS請求之中建椰。設為true雕欺,即表示服務器明確許可,Cookie可以包含在請求中棉姐,一起發(fā)給服務器屠列。

d、Access-Control-Allow-Headers: 表示允許發(fā)送的請求頭字段伞矩。CORS請求時笛洛,XMLHttpRequest對象的getResponseHeader()方法只能拿到6個基本字段:Cache-Control、Content-Language乃坤、Content-Type苛让、Expires、Last-Modified湿诊、Pragma狱杰。如果想拿到其他字段,就必須在Access-Control-Expose-Headers里面指定厅须。

e仿畸、Access-Control-Max-Age: 預檢請求的有效期,在此期間,不用發(fā)出另外一條預檢請求错沽。

在預檢請求的響應返回后簿晓,如果請求不滿足響應頭的條件,則觸發(fā)XMLHttpRequest的onerror方法甥捺,當然后面真正的CORS請求也不會發(fā)出去抢蚀。

CORS 請求的響應。現(xiàn)在它和簡單請求的情況是一樣的镰禾。瀏覽器自動加上Origin字段皿曲,服務端響應頭返回Access-Control-Allow-Origin

前端設置:

原生Ajax
jQuery ajax?

服務端設置:

服務器端對于CORS的支持吴侦,主要是通過設置Access-Control-Allow-Origin來進行的屋休。如果瀏覽器檢測到相應的設置,就可以允許Ajax進行跨域的訪問备韧。

Java設置
Node設置

2)JSONP

雖然XMLHttpRequest對象遵循同源政策劫樟,但是script標簽不一樣,它可以通過 src 填上目標地址從而發(fā)送帶有callback參數的GET 請求织堂,服務端將接口返回數據拼湊到callback函數中叠艳,返回給瀏覽器,瀏覽器解析執(zhí)行易阳,從而前端拿到callback函數返回的數據附较,實現(xiàn)跨域請求并拿到響應。這也就是 JSONP 的原理潦俺。

缺點是只支持get請求拒课,不支持post請求。適合加載不同域名的js事示、css早像,img等靜態(tài)資源。

原生
jQuery ajax
Vue.js

3)postMessage() 方法

postMessage() 方法用于安全地實現(xiàn)跨源通信肖爵。

接收頁面監(jiān)聽window的message事件就可以卢鹦。為了安全起見,我們利用這時候的MessageEvent對象判斷了一下消息源劝堪,它包括如下幾個屬性:

data:顧名思義法挨,是傳遞來的message

source:發(fā)送消息的窗口對象

origin:發(fā)送消息窗口的源(協(xié)議+主機+端口號)

4)Nginx

Nginx 是一種高性能的反向代理服務器,可以用來輕松解決跨域問題幅聘。

正向代理幫助客戶端訪問客戶端自己訪問不到的服務器凡纳,然后將結果返回給客戶端。

反向代理拿到客戶端的請求帝蒿,將請求轉發(fā)給其他的服務器荐糜,主要的場景是維持服務器集群的負載均衡,換句話說,反向代理幫其它的服務器拿到請求暴氏,然后選擇一個合適的服務器延塑,將請求轉交給它。

因此答渔,兩者的區(qū)別就很明顯了关带,正向代理服務器是幫客戶端做事情,而反向代理服務器是幫其它的服務器做事情沼撕。

比如說現(xiàn)在客戶端的域名為client.com宋雏,服務器的域名為server.com,客戶端向服務器發(fā)送 Ajax 請求务豺,當然會跨域了磨总,那這個時候讓 Nginx 登場了,通過下面這個配置:

Nginx 相當于起了一個跳板機笼沥,這個跳板機的域名也是client.com蚪燕,讓客戶端首先訪問?client.com/api,這當然沒有跨域奔浅,然后 Nginx 服務器作為反向代理馆纳,將請求轉發(fā)給server.com,當響應返回時又將響應給到客戶端汹桦,這就完成整個跨域請求的過程鲁驶。

4)document.domain + iframe跨域

此方案僅限主域相同,子域不同的跨域應用場景营勤。實現(xiàn)原理:兩個頁面都通過js強制設置document.domain為基礎主域灵嫌,就實現(xiàn)了同域壹罚。

5)postMessage跨域

postMessage是HTML5 XMLHttpRequest Level 2中的API葛作,且是為數不多可以跨域操作的window屬性之一,它可用于解決以下方面的問題:

a猖凛、頁面和其打開的新窗口的數據傳遞

b赂蠢、多窗口之間消息傳遞

c、頁面與嵌套的iframe消息傳遞

e辨泳、上面三個場景的跨域數據傳遞

用法:postMessage(data,origin)方法接受兩個參數:

data: html5規(guī)范支持任意基本類型或可復制的對象虱岂,但部分瀏覽器只支持字符串,所以傳參時最好用JSON.stringify()序列化菠红。

origin: 協(xié)議+主機+端口號第岖,也可以設置為"*",表示可以傳遞給任意窗口试溯,如果要指定和當前窗口同源的話設置為"/"蔑滓。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子键袱,更是在濱河造成了極大的恐慌燎窘,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,464評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蹄咖,死亡現(xiàn)場離奇詭異褐健,居然都是意外死亡,警方通過查閱死者的電腦和手機澜汤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,033評論 3 399
  • 文/潘曉璐 我一進店門蚜迅,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人银亲,你說我怎么就攤上這事慢叨。” “怎么了务蝠?”我有些...
    開封第一講書人閱讀 169,078評論 0 362
  • 文/不壞的土叔 我叫張陵拍谐,是天一觀的道長。 經常有香客問我馏段,道長轩拨,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,979評論 1 299
  • 正文 為了忘掉前任院喜,我火速辦了婚禮亡蓉,結果婚禮上,老公的妹妹穿的比我還像新娘喷舀。我一直安慰自己砍濒,他們只是感情好,可當我...
    茶點故事閱讀 69,001評論 6 398
  • 文/花漫 我一把揭開白布硫麻。 她就那樣靜靜地躺著爸邢,像睡著了一般。 火紅的嫁衣襯著肌膚如雪拿愧。 梳的紋絲不亂的頭發(fā)上杠河,一...
    開封第一講書人閱讀 52,584評論 1 312
  • 那天,我揣著相機與錄音浇辜,去河邊找鬼券敌。 笑死,一個胖子當著我的面吹牛柳洋,可吹牛的內容都是我干的待诅。 我是一名探鬼主播,決...
    沈念sama閱讀 41,085評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼熊镣,長吁一口氣:“原來是場噩夢啊……” “哼卑雁!你這毒婦竟也來了系宜?” 一聲冷哼從身側響起惠遏,我...
    開封第一講書人閱讀 40,023評論 0 277
  • 序言:老撾萬榮一對情侶失蹤殖蚕,失蹤者是張志新(化名)和其女友劉穎溪王,沒想到半個月后,有當地人在樹林里發(fā)現(xiàn)了一具尸體弛房,經...
    沈念sama閱讀 46,555評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡道盏,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,626評論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了文捶。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片荷逞。...
    茶點故事閱讀 40,769評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖粹排,靈堂內的尸體忽然破棺而出种远,到底是詐尸還是另有隱情,我是刑警寧澤顽耳,帶...
    沈念sama閱讀 36,439評論 5 351
  • 正文 年R本政府宣布坠敷,位于F島的核電站,受9級特大地震影響射富,放射性物質發(fā)生泄漏膝迎。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,115評論 3 335
  • 文/蒙蒙 一胰耗、第九天 我趴在偏房一處隱蔽的房頂上張望限次。 院中可真熱鬧,春花似錦柴灯、人聲如沸卖漫。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,601評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽羊始。三九已至,卻和暖如春乎串,著一層夾襖步出監(jiān)牢的瞬間店枣,已是汗流浹背速警。 一陣腳步聲響...
    開封第一講書人閱讀 33,702評論 1 274
  • 我被黑心中介騙來泰國打工叹誉, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人闷旧。 一個月前我還...
    沈念sama閱讀 49,191評論 3 378
  • 正文 我出身青樓长豁,卻偏偏與公主長得像,于是被迫代替她去往敵國和親忙灼。 傳聞我的和親對象是個殘疾皇子匠襟,可洞房花燭夜當晚...
    茶點故事閱讀 45,781評論 2 361

推薦閱讀更多精彩內容