你所不知道的跨域資源共享 (CORS)

本文收錄在www.devsai.com個人博客

寫在前面


有沒有一看到講跨域資源共享的就不想再看的了拒垃,網(wǎng)上的跨域資源共享的博文祠墅,三天兩頭的就出一篇难审。

既然你已經(jīng)進(jìn)來看了沙绝,還請你稍稍忍耐下慢蜓,繼續(xù)往下看亚再,或許你會發(fā)現(xiàn)和之前看到的有不一樣的收獲。

其實(shí)晨抡,之前看過我寫的文章的同學(xué)可能知道氛悬,我寫過一篇關(guān)于《跨域及跨域資源共享》(沒有看過的同學(xué),可以從這進(jìn)去)耘柱。比較全面的介紹了跨域的多種解決方案如捅,以及說明了跨域資源共享.

你們會不會想:那既然已經(jīng)寫過了,為什么又寫一篇调煎? 是不是博主已經(jīng)沒啥東西可寫了镜遣。

別急,接下來士袄,讓我跟你們慢慢道來悲关。

你們所知道的

看過之前寫的《跨域及跨域資源共享》或看過多篇CORS文章的同學(xué)可以選擇性的跳過這一小段了。

就像你們看到過的相關(guān)的文章娄柳,講跨域資源共享寓辱,一般講其原理時,必定要講到跨域資源共享的請求有兩種(也有很多沒有講到):

簡單請求 (Simple Request)

預(yù)檢測請求 (Preflight Request)

然后就會進(jìn)一步的講到赤拒,什么時候發(fā)只發(fā)簡單請求秫筏,又什么時候會在發(fā)真實(shí)的請求前诱鞠,先發(fā)預(yù)檢測請求,普遍的都是這么說的(包括我之前寫的也是)

以下幾種情況時都滿足時是簡單請求

request header 是簡單的請求頭

Accept

Accept-Language

Content-Language

Last-Event-ID

Content-Type

等等非自定義的請求頭

request method 是下面的請求類型

HEAD

GET

POST

Content-Type 只限三個值

application/x-www-form-urlencoded跳昼、multipart/form-data般甲、text/plain

如果不滿足以上條件的都會先發(fā)送預(yù)檢測請求,即為OPTIONS請求類型的請求

幾乎都是這么說的鹅颊,差別只是描述方式不同敷存,比例下面的別人寫的:

什么? 不信堪伍, 那你隨便搜索幾篇相關(guān)的文章看看锚烦。

那么,這有什么問題

先來做個例子吧帝雇。

假設(shè)要實(shí)現(xiàn)帶進(jìn)度條的上傳功能涮俄,接口不是同域上的,服務(wù)端已經(jīng)給配置了支持跨域資源共享的響應(yīng)頭尸闸,那我們直接用XmlHttpRequest就可以了

javaScript代碼大概如下:

varxhr =newXmlHttpRequest();xhr.onreadystatechange =function(){// do something}xhr.upload.onprogress =function(){// do something}xhr.open('POST','http://127.0.0.1/upload');varfd =newFormData();fd.append('file',file);xhr.send(fd);

然后上傳文件并查看下請求

What? 為什么會有兩個請求啊彻亲。 是不是它不滿足簡單請求的要求(已不記得簡單請求的同學(xué)往上再看看)

那么,我們來看看該真實(shí)請求的請求頭

簡單請求要求:

要求點(diǎn)實(shí)際內(nèi)容是否滿足

請求方式POST滿足

請求頭都是非自定義的請求頭滿足

Content-Typemultipart/form-data滿足

不是都滿足了嗎吮廉?那為什么苞尝,會有兩個請求,為什么在發(fā)送真實(shí)請求前還發(fā)了OPTIONS方式的請求宦芦。

為什么V嬷贰!调卑!整個人感覺都不好了B丈啊!恬涧!

變個魔術(shù)

把上面的javaScript代碼改動下:

varxhr =newXmlHttpRequest();xhr.onreadystatechange =function(){// do something}xhr.open('POST','http://127.0.0.1/upload');varfd =newFormData();fd.append('file',file);xhr.send(fd);

去掉了xhr.upload.onprogress注益,上傳后再來看下請求及請求頭:

只有一個請求,請求頭內(nèi)容還都一樣溯捆。 (這到底是怎么回事...有種再也不相信愛情的趕覺了A那场!现使!)

看到這里的同學(xué),有木有覺得博主在坑你們旷痕,放了兩張相同的請求頭截圖就想糊弄碳锈。

俗話說得好,不試不知道欺抗,一試嚇一跳售碳,要不,你們也親自試試,一試便知真假贸人。

再次雙手奉上demo(喜歡的順便點(diǎn)個贊哦~)间景。

分析問題

從上面的兩小段JS看出,只是去除了上傳的進(jìn)度信息事件艺智。也就是說加了進(jìn)度事件就多發(fā)了個預(yù)檢測請求倘要。

那么,還有沒有其他的事件了十拣?添加其他的事件會不會也會發(fā)送預(yù)檢測請求呢封拧?

事件有onerror,onloadstart等等。經(jīng)過博主的測試夭问,上述答案是肯定的泽西,添加其他事件后,確實(shí)也會發(fā)生預(yù)檢測請求缰趋。

追求真理的同學(xué)們捧杉,在博主的demo里改改試試吧。

現(xiàn)在已經(jīng)知道了問題的所在秘血,由上傳相關(guān)事件導(dǎo)致了跨域請求多發(fā)了預(yù)檢測請求味抖,說好的簡單請求(Simple Request)呢~

博主抱著對問題刨根問底的精神,再次查看cors相關(guān)文檔直撤,找到了如下的內(nèi)容:

If the following conditions are true, follow the simple cross-origin request algorithm:

The request method is a simple method and the force preflight flag is unset.

Each of the author request headers is a simple header or author request headers is empty.

通過這段非竿,我們知道,原來除了我們所知道的簡單請求的幾大特征外谋竖,還提到了force preflight flag红柱,這是什么鬼?

難道是因為設(shè)置了它蓖乘? 那么什么時候設(shè)置了force preflight flag?

上面我們知道了因為上傳事件導(dǎo)致了發(fā)送預(yù)檢測請求锤悄,會不會是上傳監(jiān)聽事件的時候給設(shè)置了force preflight flag,

然后在XmlHttpRequest level 2中的找到了相關(guān)的內(nèi)容嘉抒,以證實(shí)我的猜測是正確的零聚。

有下面幾段內(nèi)容:

force preflight flag

The upload events flag.

從這段可以知道,force preflight flag與upload events flag是對應(yīng)的,看到這里就知道了些侍,只要upload events flag被設(shè)置true

那么就等于force preflight flag被設(shè)置了true隶症,這時,不管請求的類型的是不是simple method岗宣,也不管請求頭是不是simple header蚂会,都會先發(fā)送預(yù)檢測請求。

接下來耗式,我們再來看看upload events flag會在什么情況下被設(shè)置呢胁住?

If the asynchronous flag is true and one or more event listeners are registered on the XMLHttpRequestUpload object set the upload events flag to true. Otherwise, set the upload events flag to false.

原來趁猴,當(dāng)asynchronous flag為true并且XMLHttpRequestUpload(即示例中的xhr.upload)的一個或多個事件被監(jiān)聽的時候,upload listener flag就會被設(shè)置了彪见。

這也正如之前測試的儡司,當(dāng)加了xhr.upload.onprogress后,出現(xiàn)了預(yù)檢測請求余指。

到這里總算水落石出了捕犬。

這里還需要說明的一點(diǎn)是,the asynchronous flag就是xhr.open()的第三個參數(shù)浪规,當(dāng)未設(shè)置第三參數(shù)時或听,默認(rèn)為異步,也就是the asynchronous flag為true

如果第三個參數(shù)設(shè)置為false笋婿,那么即使有上傳的監(jiān)聽事件也不會發(fā)送預(yù)檢測請求(Preflight Reuqest)

總結(jié)

以后還會不會理直氣壯的在別人面前說誉裆,只要是滿足幾大條件(是非自定義的請求頭,是GETorPOSTorHEAD,或Content-Type是那三種值的)就是簡單請求 缸濒,就不會發(fā)生預(yù)檢測請求足丢。

通過本文可知,并非滿足這幾大條件就一定是簡單請求的庇配,

應(yīng)該要加個前置條件斩跌,是否是在上傳請求中跨域,是否是異步的捞慌,是否監(jiān)聽了上傳事件耀鸦。

看到這,可能你想說啸澡,寫這么多有啥用袖订,對實(shí)際開發(fā)有幫助嗎?或許沒什么實(shí)際的幫助吧嗅虏,又或許你也不會碰到吧洛姑。

但,最起碼當(dāng)你碰到的時候皮服,你看到了兩個請求楞艾,再看了下代碼,你已經(jīng)心里就有數(shù)了龄广,知道這是怎么一回事了硫眯。

一直認(rèn)為,做技術(shù)的對碰到的問題要知其然择同,更要知其所以然舟铜。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市奠衔,隨后出現(xiàn)的幾起案子谆刨,更是在濱河造成了極大的恐慌,老刑警劉巖归斤,帶你破解...
    沈念sama閱讀 211,265評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件痊夭,死亡現(xiàn)場離奇詭異,居然都是意外死亡脏里,警方通過查閱死者的電腦和手機(jī)她我,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評論 2 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來迫横,“玉大人番舆,你說我怎么就攤上這事》猓” “怎么了恨狈?”我有些...
    開封第一講書人閱讀 156,852評論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長呛讲。 經(jīng)常有香客問我禾怠,道長,這世上最難降的妖魔是什么贝搁? 我笑而不...
    開封第一講書人閱讀 56,408評論 1 283
  • 正文 為了忘掉前任吗氏,我火速辦了婚禮,結(jié)果婚禮上雷逆,老公的妹妹穿的比我還像新娘弦讽。我一直安慰自己,他們只是感情好膀哲,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,445評論 5 384
  • 文/花漫 我一把揭開白布往产。 她就那樣靜靜地躺著,像睡著了一般等太。 火紅的嫁衣襯著肌膚如雪捂齐。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,772評論 1 290
  • 那天缩抡,我揣著相機(jī)與錄音奠宜,去河邊找鬼。 笑死瞻想,一個胖子當(dāng)著我的面吹牛压真,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播蘑险,決...
    沈念sama閱讀 38,921評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼滴肿,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了佃迄?” 一聲冷哼從身側(cè)響起泼差,我...
    開封第一講書人閱讀 37,688評論 0 266
  • 序言:老撾萬榮一對情侶失蹤贵少,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后堆缘,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體滔灶,經(jīng)...
    沈念sama閱讀 44,130評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,467評論 2 325
  • 正文 我和宋清朗相戀三年吼肥,在試婚紗的時候發(fā)現(xiàn)自己被綠了录平。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,617評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡缀皱,死狀恐怖斗这,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情啤斗,我是刑警寧澤表箭,帶...
    沈念sama閱讀 34,276評論 4 329
  • 正文 年R本政府宣布,位于F島的核電站争占,受9級特大地震影響燃逻,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜臂痕,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,882評論 3 312
  • 文/蒙蒙 一伯襟、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧握童,春花似錦姆怪、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,740評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至肥卡,卻和暖如春溪掀,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背步鉴。 一陣腳步聲響...
    開封第一講書人閱讀 31,967評論 1 265
  • 我被黑心中介騙來泰國打工揪胃, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人氛琢。 一個月前我還...
    沈念sama閱讀 46,315評論 2 360
  • 正文 我出身青樓喊递,卻偏偏與公主長得像,于是被迫代替她去往敵國和親阳似。 傳聞我的和親對象是個殘疾皇子骚勘,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,486評論 2 348

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

  • 本文詳細(xì)介紹了 XMLHttpRequest 相關(guān)知識,涉及內(nèi)容: AJAX、XMLHTTP俏讹、XMLHttpReq...
    semlinker閱讀 13,634評論 2 18
  • Ajax和XMLHttpRequest 我們通常將Ajax等同于XMLHttpRequest当宴,但細(xì)究起來它們兩個是...
    changxiaonan閱讀 2,229評論 0 2
  • 歡迎關(guān)注微信公眾號:全棧工廠 本文主要參考跨域資源共享 CORS 詳解[http://www.ruanyifeng...
    liqingbiubiu閱讀 1,828評論 0 3
  • ajax作為前端開發(fā)必需的基礎(chǔ)能力之一,你可能會使用它泽疆,但并不一定懂得其原理即供,以及更深入的服務(wù)器通信相關(guān)的知識。在...
    蕭玄辭閱讀 816評論 0 0
  • 如何提升孩子的自控力 首先于微,自控力是一種認(rèn)知過程,我們可以把“情緒控制-認(rèn)知調(diào)節(jié)-執(zhí)行控制”看作一條鏈條通道青自。舉個...
    一枚冰兒閱讀 270評論 2 1