跨域的方法

什么是同源策略椅野?

同源策略是指,瀏覽器出于安全方面的考慮榜旦,只允許與本域下的接口交互幽七。不同源的客戶端腳本在沒有明確授權(quán)的情況下,不能讀寫對方的資源溅呢。
本域包括:

什么是跨域澡屡?跨域有幾種實現(xiàn)形式?

跨域即在不同的域(協(xié)議咐旧、域名驶鹉、端口中有任意一個不同)之間發(fā)起請求,打破同源策略的限制铣墨,訪問其他域的數(shù)據(jù)室埋。
跨域的實現(xiàn)方式有:

  • JSONP
  • CORS
  • 降域
  • postMessage

JSONP

JSONP是JSON的一種使用方式,利用script標(biāo)簽可以跨域引用的特點伊约,對跨域的數(shù)據(jù)進行請求专酗,該方法需要后端數(shù)據(jù)配合尤蛮。
使用JSONP的步驟:

  • 本地創(chuàng)建一個數(shù)據(jù)處理函數(shù)func疏叨;
  • 利用script標(biāo)簽浅萧,設(shè)置src路徑為向服務(wù)器發(fā)送請求的端口,同時加上參數(shù)callBack = func超埋,用于提供后端反饋數(shù)據(jù)的接口搏讶;
  • 服務(wù)端在收到請求后,解析參數(shù)霍殴,計算返還數(shù)據(jù)窍蓝,輸出 fun(data) 字符串。
  • fun(data)會放到script標(biāo)簽做為js執(zhí)行繁成。此時會調(diào)用fun函數(shù),將data做為參數(shù)淑玫。

演示舉例:

  1. 修改hosts文件巾腕,模擬跨域請求失斆婢Α;


    image.png
  • HTML中尊搬,通過查詢城市名字叁鉴,獲取對應(yīng)天氣及圖片


    image.png
  • js中請求為:


    image.png
  • 瀏覽器訪問http://a.com:8080
    形成跨域,從控制臺看到佛寿,響應(yīng)到了瀏覽器之后不被允許

    image.png

2.使用JSONP修改js請求

  • 客戶端用script向后端發(fā)送請求


    image.png
  • 服務(wù)端響應(yīng)幌墓,提供對應(yīng)城市的天氣和圖片


    image.png

    image.png
  • 效果,訪問a.com冀泻,請求127.0.0.1


    image.png

CORS

CORS 全稱是跨域資源共享(Cross-Origin Resource Sharing)常侣,是一種 ajax 跨域請求資源的方式,支持現(xiàn)代瀏覽器弹渔,IE支持10以上胳施。
瀏覽器將CORS請求分成兩類:簡單請求(simple request)和非簡單請求(not-so-simple request)。

簡單請求

只要同時滿足以下兩大條件肢专,就屬于簡單請求舞肆。
(1) 請求方法是以下三種方法之一:
HEAD
GET
POST
(2)HTTP的頭信息不超出以下幾種字段:
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type:只限于三個值application/x-www-form-urlencoded、multipart/form-data博杖、text/plain

瀏覽器請求

對于簡單請求椿胯,瀏覽器直接發(fā)出CORS請求。具體來說剃根,就是在頭信息之中哩盲,增加一個Origin字段。


image.png

服務(wù)器回應(yīng)

如果Origin指定的源跟继,不在許可范圍內(nèi)种冬,服務(wù)器會返回一個正常的HTTP回應(yīng)。瀏覽器發(fā)現(xiàn)舔糖,這個回應(yīng)的頭信息沒有包含Access-Control-Allow-Origin字段(詳見下文)娱两,就知道出錯了,從而拋出一個錯誤金吗,被XMLHttpRequest的onerror回調(diào)函數(shù)捕獲十兢。注意,這種錯誤無法通過狀態(tài)碼識別摇庙,因為HTTP回應(yīng)的狀態(tài)碼有可能是200旱物。
如果Origin指定的域名在許可范圍內(nèi),服務(wù)器返回的響應(yīng)卫袒,會多出幾個頭信息字段宵呛。


image.png

Access-Control-Allow-Origin,該字段是必須的夕凝。它的值要么是請求時Origin字段的值宝穗,要么是一個*户秤,表示接受任意域名的請求。

非簡單請求

非簡單請求是那種對服務(wù)器有特殊要求的請求逮矛,比如請求方法是PUT或DELETE鸡号,或者Content-Type字段的類型是application/json。

瀏覽器請求

非簡單請求的CORS請求须鼎,會在正式通信之前鲸伴,增加一次HTTP查詢請求,稱為"預(yù)檢"請求(preflight)晋控。
瀏覽器先詢問服務(wù)器汞窗,當(dāng)前網(wǎng)頁所在的域名是否在服務(wù)器的許可名單之中,以及可以使用哪些HTTP動詞和頭信息字段糖荒。只有得到肯定答復(fù)杉辙,瀏覽器才會發(fā)出正式的XMLHttpRequest請求,否則就報錯捶朵。

image.png

上面代碼中蜘矢,HTTP請求的方法是PUT,并且發(fā)送一個自定義頭信息X-Custom-Header综看。
瀏覽器發(fā)現(xiàn)品腹,這是一個非簡單請求,就自動發(fā)出一個"預(yù)檢"請求红碑,要求服務(wù)器確認可以這樣請求舞吭。下面是這個"預(yù)檢"請求的HTTP頭信息。

image.png

服務(wù)器回應(yīng)

服務(wù)器收到"預(yù)檢"請求以后析珊,檢查了Origin羡鸥、Access-Control-Request-Method和Access-Control-Request-Headers字段以后,確認允許跨源請求忠寻,就可以做出回應(yīng)惧浴。


image.png

上面的HTTP回應(yīng)中,關(guān)鍵的是Access-Control-Allow-Origin字段奕剃,表示http://api.bob.com可以請求數(shù)據(jù)衷旅。該字段也可以設(shè)為星號,表示同意任意跨源請求纵朋。
Access-Control-Allow-Methods柿顶,該字段必需,它的值是逗號分隔的一個字符串操软,表明服務(wù)器支持的所有跨域請求的方法嘁锯。注意,返回的是所有支持的方法猪钮,而不單是瀏覽器請求的那個方法。這是為了避免多次"預(yù)檢"請求

如果瀏覽器否定了"預(yù)檢"請求,會返回一個正常的HTTP回應(yīng)笆载,但是沒有任何CORS相關(guān)的頭信息字段扑馁。這時,瀏覽器就會認定腻要,服務(wù)器不同意預(yù)檢請求涝登,因此觸發(fā)一個錯誤雄家,被XMLHttpRequest對象的onerror回調(diào)函數(shù)捕獲≌凸觯控制臺會打印出如下的報錯信息。


image.png
說明:以上參考引用了跨域資源共享 CORS 詳解 ---by 阮一峰

演示舉例

客戶端請求:


image.png

服務(wù)器端響應(yīng):


image.png

效果:


image.png

訪問a.com,請求為127.0.0.1媳纬,實現(xiàn)跨域

降域

瀏覽器內(nèi)部做了限制施掏,只有同域名下的頁面才能用JS去獲取和操作iframe頁面,否則只能加載素挽,但不能用外部JS去獲取和操作
通過設(shè)置document.domain的方式抖苦,將兩個域名的domain設(shè)置為一個锌历,如對于a.test.com和b.test.com,可以通過js設(shè)置document.domain = "test.com"究西,實現(xiàn)跨域

演示舉例:

a.test.com:8080下的a.html內(nèi)嵌了一個iframe,src為http://b.test.com:8080/b.html
正常情況下峦失,因為a,b不同源术吗,a不能修改內(nèi)嵌的iframe中輸入框的內(nèi)容;

image.png

image.png

但通過降域:document.domain = 'test.com';使得a可以修改內(nèi)嵌的b中的內(nèi)容


image.png

postMessage

postMessage是一個web API,可以實現(xiàn)跨域通信隘蝎。window.postMessage()被調(diào)用時,會在所有頁面腳本執(zhí)行完畢后狮含,向目標(biāo)窗口派發(fā)一個MessageEvent消息。語法如下:

otherWindow.postMessage(message, targetOrigin, [transfer]);
  • otherwindow
    其他窗口的一個引用几迄,比如iframe的contentWindow屬性拴测、執(zhí)行window.open返回的窗口對象集索、或者是命名過或數(shù)值索引的window.frames。
  • message
    將要發(fā)送到其他 window的數(shù)據(jù)妆距。它將會被結(jié)構(gòu)化克隆算法序列化函匕。這意味著你可以不受什么限制的將數(shù)據(jù)對象安全的傳送給目標(biāo)窗口而無需自己序列化盅惜。
  • targetOrigin
    通過窗口的origin屬性來指定哪些窗口能接收到消息事件,其值可以是字符串*(表示無限制)或者一個URI结啼。在發(fā)送消息的時候屈芜,如果目標(biāo)窗口的協(xié)議、主機地址或端口這三者的任意一項不匹配targetOrigin提供的值属铁,那么消息就不會被發(fā)送焦蘑;只有三者完全匹配,消息才會被發(fā)送坟乾。這個機制用來控制消息可以發(fā)送到哪些窗口蝶防;例如间学,當(dāng)用postMessage傳送密碼時印荔,這個參數(shù)就顯得尤為重要,必須保證它的值與這條包含密碼的信息的預(yù)期接受者的orign屬性完全一致嘿悬,來防止密碼被惡意的第三方截獲水泉。如果你明確的知道消息應(yīng)該發(fā)送到哪個窗口草则,那么請始終提供一個有確切值的targetOrigin,而不是*源内。不提供確切的目標(biāo)將導(dǎo)致數(shù)據(jù)泄露到任何對數(shù)據(jù)感興趣的惡意站點份殿。
  • transfer(可選)
    是一串和message 同時傳遞的Transferable對象. 這些對象的所有權(quán)將被轉(zhuǎn)移給消息的接收方卿嘲,而發(fā)送一方將不再保有所有權(quán)

message 的屬性有:

  • data
    從其他 window 中傳遞過來的對象
  • origin
    調(diào)用postMessage時消息發(fā)送方窗口的origin,這個字符串由 協(xié)議焚鲜、“://“、域名糯彬、“ : 端口號”拼接而成撩扒。請注意吨些,這個origin不能保證是該窗口的當(dāng)前或未來origin,因為postMessage被調(diào)用后可能被導(dǎo)航到不同的位置泉手。
  • source
    對發(fā)送消息的窗口對象的引用; 您可以使用此來在具有不同origin的兩個窗口之間建立雙向通信

安全問題:

如果不希望從其他網(wǎng)站接收message斩萌,請不要為message事件添加任何事件偵聽器屏轰。 這是一個完全萬無一失的方式來避免安全問題。
如果確實希望從其他網(wǎng)站接收message姆吭,請始終使用origin和source屬性驗證發(fā)件人的身份内狸。 任何窗口(包括例如http://evil.example.com)都可以向任何其他窗口發(fā)送消息升敲,并且不能保證未知發(fā)件人不會發(fā)送惡意消息驴党。 但是,驗證身份后倔既,仍然應(yīng)該始終驗證接收到的消息的語法鹏氧。 否則,信任只發(fā)送受信任郵件的網(wǎng)站中的安全漏洞可能會在網(wǎng)站中打開跨網(wǎng)站腳本漏洞实蓬。
當(dāng)使用postMessage將數(shù)據(jù)發(fā)送到其他窗口時安皱,始終指定精確的目標(biāo)origin,而不是*腾窝。 惡意網(wǎng)站可以在您不知情的情況下更改窗口的位置居砖,因此它可以攔截使用postMessage發(fā)送的數(shù)據(jù)奏候。

說明:以上參考引用了MDN:window.postMessage

演示舉例

a中內(nèi)嵌b的iframe,同時向http://b.test.com:8080發(fā)送post消息暇榴;
并監(jiān)聽post消息,確認origin來自b婆硬,才使用消息內(nèi)容彬犯;

image.png

b中做同樣處理,向a發(fā)送postmessage湖蜕,同時監(jiān)聽消息昭抒,確認來源為a


image.png

效果:


image.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末灭返,一起剝皮案震驚了整個濱河市熙含,隨后出現(xiàn)的幾起案子艇纺,更是在濱河造成了極大的恐慌,老刑警劉巖蚓聘,帶你破解...
    沈念sama閱讀 216,470評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件或粮,死亡現(xiàn)場離奇詭異氯材,居然都是意外死亡,警方通過查閱死者的電腦和手機袋毙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評論 3 392
  • 文/潘曉璐 我一進店門听盖,熙熙樓的掌柜王于貴愁眉苦臉地迎上來裂七,“玉大人背零,你說我怎么就攤上這事∶停” “怎么了侦镇?”我有些...
    開封第一講書人閱讀 162,577評論 0 353
  • 文/不壞的土叔 我叫張陵壳繁,是天一觀的道長闹炉。 經(jīng)常有香客問我,道長诉植,這世上最難降的妖魔是什么昵观? 我笑而不...
    開封第一講書人閱讀 58,176評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮壁查,結(jié)果婚禮上剔应,老公的妹妹穿的比我還像新娘峻贮。我一直安慰自己,他們只是感情好挂捻,可當(dāng)我...
    茶點故事閱讀 67,189評論 6 388
  • 文/花漫 我一把揭開白布刻撒。 她就那樣靜靜地躺著耿导,像睡著了一般舱呻。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,155評論 1 299
  • 那天殖氏,我揣著相機與錄音姻采,去河邊找鬼慨亲。 笑死,一個胖子當(dāng)著我的面吹牛巴刻,可吹牛的內(nèi)容都是我干的蛉签。 我是一名探鬼主播,決...
    沈念sama閱讀 40,041評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼邑雅,長吁一口氣:“原來是場噩夢啊……” “哼妈经!你這毒婦竟也來了吹泡?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,903評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎泪漂,沒想到半個月后萝勤,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,319評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡慎式,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,539評論 2 332
  • 正文 我和宋清朗相戀三年瘪吏,在試婚紗的時候發(fā)現(xiàn)自己被綠了掌眠。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片幕屹。...
    茶點故事閱讀 39,703評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡望拖,死狀恐怖说敏,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情锌雀,我是刑警寧澤,帶...
    沈念sama閱讀 35,417評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站惩歉,受9級特大地震影響撑蚌,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜粉楚,卻給世界環(huán)境...
    茶點故事閱讀 41,013評論 3 325
  • 文/蒙蒙 一模软、第九天 我趴在偏房一處隱蔽的房頂上張望饮潦。 院中可真熱鬧继蜡,春花似錦、人聲如沸稀并。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,664評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽枚抵。三九已至汽摹,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間趴泌,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,818評論 1 269
  • 我被黑心中介騙來泰國打工秃励, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留夺鲜,地道東北人呐舔。 一個月前我還...
    沈念sama閱讀 47,711評論 2 368
  • 正文 我出身青樓珊拼,卻偏偏與公主長得像,于是被迫代替她去往敵國和親仅胞。 傳聞我的和親對象是個殘疾皇子饼问,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,601評論 2 353

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