您好,登錄后才能下訂單哦!
web開發(fā)隨著ajax的出來帶來了革命性的變化,它改變了web的數(shù)據(jù)加載方式讓交互更友好,網(wǎng)絡(luò)資源更節(jié)省。但最初ajax考慮安全性并沒有開放跨域請(qǐng)求,隨著H5的到來ajax開放了跨域請(qǐng)求,所以ajax跨域請(qǐng)求存在兼容性,不過現(xiàn)在的瀏覽器大部分都已經(jīng)支持了。
常用跨域請(qǐng)求手段有:
jsonp
FORM到頁(yè)面框架
HTTP服務(wù)器代理
服務(wù)器腳本轉(zhuǎn)發(fā)
ajax
WebSocket
插件
jsonp
這種方式是早期在ajax不支持跨域請(qǐng)求時(shí)的一種替代方案應(yīng)用非常多,在JQuery類的早期框架都集成了此功能。期原理就是通過HTML的<script>標(biāo)簽加載一個(gè)跨域的請(qǐng)求地址并指定一個(gè)隨機(jī)回調(diào)函數(shù),所連接的服務(wù)器返回指定的回調(diào)函數(shù)并增加參數(shù),標(biāo)簽加載完后會(huì)自動(dòng)執(zhí)行代碼來完成請(qǐng)求回調(diào),因此jsonp只支持GET請(qǐng)求方式,并且需要服務(wù)器作專用處理,典型的示例如:
前端代碼:(域名www.a.cn請(qǐng)求域名www.b.cn)
(function?(global)?{ ????//發(fā)送請(qǐng)求 ????function?request(url,?data,?callback)?{ ????????function?jsonpcall(_data,?error)?{ ????????????callback(_data,?error); ????????????//清理 ????????????delete?global[data['jsonpcallback']]; ????????????document.body.removeChild(script); ????????} ????????data?=?data?||?{}; ????????//生成全局回調(diào)函數(shù) ????????data['jsonpcallback']?=?'jsonp_'?+?String(Math.random()).substr(2,?10); ????????global[data['jsonpcallback']]?=?jsonpcall; ????????var?params?=?getParamsString(data); ????????var?script?=?document.createElement('script'); ????????script.type?=?'text/javascript'; ????????script.src?=?url?+?(url.indexOf('?')?>=?0???'&'?:?'?')?+?params; ????????script.onerror?=?function?(event)?{ ????????????jsonpcall(null,?event); ????????}; ????????document.body.appendChild(script); ????} ????//轉(zhuǎn)換請(qǐng)求參數(shù) ????function?getParamsString(data,?prefix)?{ ????????var?arr?=?[]; ????????prefix?=?prefix?||?''; ????????for?(var?key?in?data)?{ ????????????var?name?=?''; ????????????if?(!prefix)?{ ????????????????name?=?key; ????????????}?else?{ ????????????????name?=?prefix?+?'['?+?key?+?']'; ????????????} ????????????if?(typeof?data[key]?===?'object')?{ ????????????????arr.push(getParamsString(data[key],?name)); ????????????}?else?{ ????????????????arr.push(name?+?'='?+?data[key]); ????????????} ????????} ????????return?arr.join('&'); ????} ????global.jsonp?=?request; })(window); //發(fā)起請(qǐng)求 jsonp('http://www.b.cn',?{id:?12},?function?()?{ ????console.info(arguments); });
服務(wù)端代碼:(域名www.b.cn,以PHP為例)
<?php if?(empty($_GET['jsonpcallback']))?{ ????header('HTTP/1.1?404?Not?Found'); ????die(); } //查數(shù)據(jù),返回結(jié)果 $data?=?[ ????'status'?=>?'ok', ????'msg'?=>?'操作成功' ]; //輸出結(jié)果 echo?$_GET['jsonpcallback']?.?'('?.?json_encode($data,?JSON_UNESCAPED_UNICODE)?.?');';
這種方式請(qǐng)求不受跨域限制使用方便,兼容性好,非常適用小數(shù)據(jù)量跨域請(qǐng)求。缺點(diǎn)是只支持GET請(qǐng)求無(wú)法完成像上傳文件或其它請(qǐng)求方式的操作,服務(wù)器響應(yīng)結(jié)果專用性強(qiáng)。
FORM到頁(yè)面框架
這種方式在異步上傳文件使用非常多,通常是iframe+form結(jié)合通過form的target屬性指定到iframe的name完成異步請(qǐng)求,但iframe有部分移動(dòng)端存瀏覽器不支持,另外還有一個(gè)frameset標(biāo)簽在H5中已經(jīng)不支持。
使用這種方式跨域請(qǐng)求兼容性僅僅在PC端較好而且服務(wù)端不需要作額外處理,但移動(dòng)端上使用需要留意用戶平臺(tái)是否都支持。典型的示例如:
//?請(qǐng)求處理 function?request(form,?callback)?{ ????var?iframe?=?document.createElement('iframe'),?name?=?'IFRAME-'?+?String(Math.random()).replace('.',?''),?submit?=?1; ????iframe.name?=?name,?form.target?=?name; ????iframe.onload?=?function?()?{ ????????//初次加載 ????????if?(submit?===?1)?{ ????????????form.submit(); ????????}?else?if?(submit?===?2)?{ ????????????try?{ ????????????????var?json?=?JSON.parse((iframe.contentDocument?||?iframe.contentWindow.document).body.innerHTML); ????????????????callback(json); ????????????}?catch?(err)?{ ????????????????callback(null,?err); ????????????} ????????????document.body.removeChild(iframe); ????????} ????????submit++; ????}; ????iframe.onerror?=?function?(event)?{ ????????callback(null,?event); ????????document.body.removeChild(iframe); ????}; ????//不能顯示標(biāo)簽 ????iframe.style.display?=?'none'; ????document.body.appendChild(iframe); } //發(fā)送請(qǐng)求 request(document.forms[0],?function(){ ????console.info(arguments); });
這種方式間接完成跨域操作,同時(shí)對(duì)服務(wù)端的代碼沒有額外要求,只需要返回一個(gè)通用的json串即可,通過這個(gè)方式可以完成GET與POST請(qǐng)求并且還可以上傳文件,最大的缺點(diǎn)是有少部分瀏覽器不支持。
HTTP服務(wù)器代理
這種方式從理論上說不需要開發(fā)額外的代碼只需要在HTTP服務(wù)器上配置代理轉(zhuǎn)發(fā)即可以滿足所有請(qǐng)求的跨域請(qǐng)求,但會(huì)額外增加服務(wù)器性能開銷,不適合于跨域請(qǐng)求過多的場(chǎng)景,畢竟服務(wù)器的資源是有限的。一般使用這種方式的基本上是小項(xiàng)目,大項(xiàng)目這么玩在硬件上開銷不容忽視。以nginx為例,典型的配置代碼有:(僅以server塊為例)
????location?/proxy?{ ??????????#?resolver?114.114.114.114?223.5.5.5?valid=3600s; ??????????proxy_pass?http://www.b.com:8099/; ????}
nginx的proxy_pass做代理配置很容易,配置靈活。
如果在proxy_pass中指定了詳細(xì)地址則只轉(zhuǎn)發(fā)到對(duì)應(yīng)的地址
如果沒有指定地址則把當(dāng)前的地址追加到域名下
如果需要指定DNS解析地址則可以增加resolver命令,但一定要保證DNS服務(wù)器正常,否則請(qǐng)求會(huì)卡住
轉(zhuǎn)發(fā)可以使用IP地址和域名,如果有特定端口一定要追加上
域名可以使用變量來傳入,例如:set $proxy_host "http://www.b.com:8099/";? proxy_pass $proxy_host;
可以指定路徑,也可以通過if來判斷
nginx配置代理調(diào)試比較麻煩需要多注意兩個(gè)日志文件。對(duì)于配置要考慮:
是否被截取即沒有進(jìn)入代理塊
代理域名端口協(xié)議是否正確
域名或地址是否能正常訪問
服務(wù)器腳本轉(zhuǎn)發(fā)
這種方式是通過服務(wù)器的腳本來轉(zhuǎn)發(fā),避開前端跨域請(qǐng)求,開發(fā)方便,對(duì)于配置HTTP服務(wù)器有限制或問題時(shí)是一個(gè)比較簡(jiǎn)單的替代方案。本質(zhì)與HTTP服務(wù)器代理類似,都是通過服務(wù)器來轉(zhuǎn)來,不可避免增加服務(wù)器的開銷。這種處理方式唯一的好處是開發(fā)調(diào)試容易,兼容性好。以PHP為例,典型的示例代碼如:
$url?=?$_GET['_url_']; $input?=?file_get_contents('php://input'); $curl?=?curl_init(); curl_setopt_array($curl,?[ ????CURLOPT_HTTP_VERSION?=>?CURL_HTTP_VERSION_1_1, ????CURLOPT_USERAGENT?=>?'Mozilla/5.0?(Windows?NT?10.0;?WOW64)?AppleWebKit/537.36?(KHTML,?like?Gecko)?Chrome/41.0.2272.118?Safari/537.36', ????CURLOPT_CONNECTTIMEOUT?=>?10, ????CURLOPT_TIMEOUT?=>?30, ????CURLOPT_RETURNTRANSFER?=>?true, ????CURLOPT_SSL_VERIFYPEER?=>?FALSE,?//?不驗(yàn)證證書 ????CURLOPT_SSL_VERIFYHOST?=>?FALSE,?//?不驗(yàn)證域名 ]); if?($_SERVER['REQUEST_METHOD']?==?'POST')?{ ????curl_setopt($curl,?CURLOPT_POST,?true); ????curl_setopt($curl,?CURLOPT_POSTFIELDS,?$input); ????curl_setopt($curl,?CURLOPT_URL,?$url); }?else?{ ????unset($_GET['_url_']); ????$params?=?http_build_query($_GET); ????curl_setopt($curl,?CURLOPT_URL,?$url?.?(strpos($url,?'?')???'&'?:?'?')?.?$params); } $response?=?curl_exec($curl); $httpCode?=?curl_getinfo($curl,?CURLINFO_HTTP_CODE); curl_close($curl); header('HTTP/1.1?'?.?$httpCode); echo?$response;
代碼中簡(jiǎn)單的示例通過curl發(fā)起跨域請(qǐng)求,前端只需要指定需要請(qǐng)求的跨域地址和參數(shù)即可完成請(qǐng)求操作,由于請(qǐng)求類型多樣化,所以使用代碼轉(zhuǎn)發(fā)要做到兼容所有請(qǐng)求形式則需要做較多的處理,一般用不上。
ajax
ajax支持跨域可以說可以非常理想,遺憾的時(shí)推出的晚,不過現(xiàn)在隨著瀏覽器全面支持H5使得ajax跨域請(qǐng)求變得普及起來,如果應(yīng)用平臺(tái)涉及比較老的瀏覽器則需要留意了。官方文檔:https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS?在官方文檔中有比較詳細(xì)的說明。
其實(shí)從本質(zhì)上說跨域限制只是瀏覽器出于安全考慮的一個(gè)限制,而開放這個(gè)限制也需要合理安全,否則會(huì)造成比較多的跨域請(qǐng)求漏洞,因此瀏覽器對(duì)ajax跨域請(qǐng)求作了一些限制,它必需要服務(wù)器返回允許跨域響應(yīng)頭信息,才正常提供響應(yīng)結(jié)果,所以ajax跨域請(qǐng)求需要服務(wù)端額外增加響應(yīng)頭信息。
ajax跨域請(qǐng)求分為兩種場(chǎng)景:基本請(qǐng)求,預(yù)檢請(qǐng)求;并且XMLHttpRequest內(nèi)部通過指定條件強(qiáng)制判斷識(shí)別并作出相應(yīng)的操作,其中預(yù)檢請(qǐng)求會(huì)觸發(fā)CORS預(yù)檢,CORS預(yù)檢會(huì)把請(qǐng)求類型強(qiáng)制修改為OPTIONS類型向服務(wù)器發(fā)起跨域請(qǐng)求檢查服務(wù)器是否響應(yīng)允許跨域請(qǐng)求頭信息如果允許則再次發(fā)起指定的請(qǐng)求類型跨域請(qǐng)求并把響應(yīng)內(nèi)容注入到ajax響應(yīng)內(nèi)容中,而基本請(qǐng)求是直接發(fā)起指定請(qǐng)求類型的跨域請(qǐng)求。兩種請(qǐng)求場(chǎng)景均需要跨域服務(wù)器返回允許跨域響應(yīng)頭信息,響應(yīng)狀態(tài)等頭信息不會(huì)受影響。
常規(guī)請(qǐng)求
這種場(chǎng)景瀏覽器會(huì)直接發(fā)起請(qǐng)求,當(dāng)響應(yīng)頭信息內(nèi)容中不包含Access-Control-Allow-Origin允許頭信息時(shí)會(huì)丟棄響應(yīng)內(nèi)容并向控制臺(tái)發(fā)出Failed to load警告信息,提示服務(wù)器沒有Access-Control-Allow-Origin響應(yīng)頭信息請(qǐng)求不被允許。
條件:(需全部滿足)
請(qǐng)求類型為 GET、HEAD、POST
僅設(shè)置過Accept、Accept-Language、Content-Language、Content-Type、DPR、Downlink、Save-Data、Viewport-Width、Width頭信息,或使用默認(rèn)的不設(shè)置頭信息
Content-Type只能設(shè)置為application/x-www-form-urlencoded、multipart/form-data、text/plain,或者不設(shè)置
在請(qǐng)求中沒有使用過XMLHttpRequestUpload事件監(jiān)聽。XMLHttpRequestUpload是通過XMLHttpRequest對(duì)象的upload屬性獲取的一個(gè)上傳進(jìn)度對(duì)象,可以獲取上傳進(jìn)度數(shù)據(jù)。
請(qǐng)求中沒有使用ReadableStream對(duì)象。ReadableStream大部分瀏覽器還不支持,是一個(gè)獲取響應(yīng)二進(jìn)度流的對(duì)象處理器。
示例代碼:(只在不觸犯以上任何一個(gè)條件即可)
(function?(global)?{ ????function?request(url,?callback,?data,?method)?{ ????????var?xmlHttp?=?new?XMLHttpRequest(); ????????var?params?=?getParamsString(data?||?{}); ????????method?=?method?||?'GET'; ????????if?(method.toUpperCase()?===?'POST')?{ ????????????xmlHttp.open(method,?url,?true); ????????????xmlHttp.setRequestHeader('Content-Type',?'application/x-www-form-urlencoded;'); ????????????xmlHttp.send(params); ????????}?else?{ ????????????xmlHttp.open(method,?url?+?(url.indexOf('?')?>=?0???'&'?:?'?')?+?params,?true); ????????????xmlHttp.send(null); ????????} ????????xmlHttp.onreadystatechange?=?function?()?{ ????????????if?(xmlHttp.readyState?==?4)?{ ????????????????try?{ ????????????????????if?(xmlHttp.status?==?200)?{ ????????????????????????var?json?=?JSON.parse(xmlHttp.responseText); ????????????????????????callback(json); ????????????????????}?else?{ ????????????????????????callback(null,?xmlHttp.responseText); ????????????????????} ????????????????}?catch?(err)?{ ????????????????????callback(null,?err); ????????????????} ????????????} ????????}; ????} ????//轉(zhuǎn)換請(qǐng)求參數(shù) ????function?getParamsString(data,?prefix)?{ ????????var?arr?=?[]; ????????prefix?=?prefix?||?''; ????????for?(var?key?in?data)?{ ????????????var?name?=?''; ????????????if?(!prefix)?{ ????????????????name?=?key; ????????????}?else?{ ????????????????name?=?prefix?+?'['?+?key?+?']'; ????????????} ????????????if?(typeof?data[key]?===?'object')?{ ????????????????arr.push(getParamsString(data[key],?name)); ????????????}?else?{ ????????????????arr.push(name?+?'='?+?data[key]); ????????????} ????????} ????????return?arr.join('&'); ????} ????global.ajax?=?request; })(window); //發(fā)起請(qǐng)求 ajax('https://www.b.cn/',?function?()?{ ????console.info(arguments); });
預(yù)檢請(qǐng)求
這種場(chǎng)景請(qǐng)求瀏覽器會(huì)強(qiáng)制把請(qǐng)求類型改為OPTIONS類型發(fā)起預(yù)檢跨域請(qǐng)求,當(dāng)響應(yīng)頭信息內(nèi)容中不包含Access-Control-Allow-Origin允許頭信息時(shí)會(huì)丟棄響應(yīng)內(nèi)容并向控制臺(tái)發(fā)出Failed to load警告信息,提示服務(wù)器沒有Access-Control-Allow-Origin響應(yīng)頭信息請(qǐng)求不被允許;如果響應(yīng)頭信息全部允許跨域請(qǐng)求則瀏覽器會(huì)再次發(fā)送指定請(qǐng)求類型的跨域請(qǐng)求到服務(wù)器并獲取本次響應(yīng)內(nèi)容注入到ajax的響應(yīng)內(nèi)容中。
條件:(任意條滿足)
請(qǐng)求類型指定為:PUT、DELETE、CONNECT、OPTIONS、TRACE、PATCH
設(shè)置了Accept、Accept-Language、Content-Language、Content-Type、DPR、Downlink、Save-Data、Viewport-Width、Width之外的頭信息
設(shè)置Content-Type是為application/x-www-form-urlencoded、multipart/form-data、text/plain之外的類型
在請(qǐng)求中使用過XMLHttpRequestUpload事件監(jiān)聽
請(qǐng)求中使用ReadableStream對(duì)象
示例代碼:(強(qiáng)制增加一個(gè)特殊頭信息即可)
(function?(global)?{ ????function?request(url,?callback,?data,?method)?{ ????????var?xmlHttp?=?new?XMLHttpRequest(); ????????var?params?=?getParamsString(data?||?{}); ????????method?=?method?||?'GET'; ????????if?(method.toUpperCase()?===?'POST')?{ ????????????xmlHttp.open(method,?url,?true); ????????????xmlHttp.setRequestHeader('Ajax-Request',?'1'); ????????????xmlHttp.setRequestHeader('Content-Type',?'application/x-www-form-urlencoded;'); ????????????xmlHttp.send(params); ????????}?else?{ ????????????xmlHttp.open(method,?url?+?(url.indexOf('?')?>=?0???'&'?:?'?')?+?params,?true); ????????????xmlHttp.setRequestHeader('Ajax-Request',?'1'); ????????????xmlHttp.setRequestHeader('Content-Type',?'text/html'); ????????????xmlHttp.send(null); ????????} ????????xmlHttp.onreadystatechange?=?function?()?{ ????????????if?(xmlHttp.readyState?==?4)?{ ????????????????try?{ ????????????????????if?(xmlHttp.status?==?200)?{ ????????????????????????var?json?=?JSON.parse(xmlHttp.responseText); ????????????????????????callback(json); ????????????????????}?else?{ ????????????????????????callback(null,?xmlHttp.responseText); ????????????????????} ????????????????}?catch?(err)?{ ????????????????????callback(null,?err); ????????????????} ????????????} ????????}; ????} ????//轉(zhuǎn)換請(qǐng)求參數(shù) ????function?getParamsString(data,?prefix)?{ ????????var?arr?=?[]; ????????prefix?=?prefix?||?''; ????????for?(var?key?in?data)?{ ????????????var?name?=?''; ????????????if?(!prefix)?{ ????????????????name?=?key; ????????????}?else?{ ????????????????name?=?prefix?+?'['?+?key?+?']'; ????????????} ????????????if?(typeof?data[key]?===?'object')?{ ????????????????arr.push(getParamsString(data[key],?name)); ????????????}?else?{ ????????????????arr.push(name?+?'='?+?data[key]); ????????????} ????????} ????????return?arr.join('&'); ????} ????global.ajax?=?request; })(window); //發(fā)起請(qǐng)求 ajax('https://www.b.cn/',?function?()?{ ????console.info(arguments); });
攜帶請(qǐng)求資源
在跨域請(qǐng)求時(shí)還允許攜帶請(qǐng)求資源如cookie,但必需設(shè)置XMLHttpRequest對(duì)象的withCredentials屬性為true,如:
xmlHttp.withCredentials?=?true;
攜帶的請(qǐng)求資源受,響應(yīng)頭信息Access-Control-Allow-Origin、Access-Control-Allow-Credentials兩個(gè)影響,Access-Control-Allow-Origin必需指定為當(dāng)前請(qǐng)求的域名,Access-Control-Allow-Credentials必需設(shè)置為true否則跨域請(qǐng)求攜帶資源失敗即服務(wù)器返回的cookie不會(huì)被記錄。跨域請(qǐng)求只受Access-Control-Allow-Origin影響,只要Access-Control-Allow-Origin允許當(dāng)前域名則請(qǐng)求可以正常獲取響應(yīng)結(jié)果。
注意:如果設(shè)置這個(gè)值,Access-Control-Allow-Origin指定為通配符有兼容問題,需要設(shè)置為對(duì)應(yīng)的域名集。
跨域請(qǐng)求響應(yīng)頭信息
這些頭信息由服務(wù)器響應(yīng),瀏覽器內(nèi)核判斷并作相應(yīng)處理。這些頭信息是預(yù)定好的,只需要按規(guī)則響應(yīng)返回給瀏覽即可完成跨域請(qǐng)求。瀏覽器對(duì)這些頭信息處理略有差異,不建議設(shè)計(jì)的太隨意畢竟安全還是比較重要的。
Access-Control-Allow-Origin
該頭信息是跨域請(qǐng)求中必需響應(yīng)的,它用來標(biāo)識(shí)服務(wù)器允許哪些請(qǐng)求來源域名共享數(shù)據(jù),一般如果沒有特別要求最好設(shè)置為指定的開放域名。如果允許任意域名使用*通配符。如果是指定一個(gè)域名并且每次請(qǐng)求該響應(yīng)頭均會(huì)變化則需要增加Vary: Origin頭信息來禁止瀏覽器的緩存。
Access-Control-Expose-Headers
該頭信息允許暴露給外部的頭信息,默認(rèn)只可以暴露服務(wù)器響應(yīng)Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma頭信息。如果想讓腳本通過XMLHttpRequest對(duì)象的getAllResponseHeaders()函數(shù)訪問到其它頭信息則可以在這里設(shè)置,多個(gè)以逗號(hào)分開也可以使用通配符*。注意預(yù)檢請(qǐng)求中詢問成功后才有效。
Access-Control-Max-Age
該狀信息用于預(yù)檢請(qǐng)求中Access-Control-Allow-Methods、Access-Control-Allow-Headers信息可以緩存多久,單位為秒,每個(gè)瀏覽器中最大秒數(shù)有限制,火狐中最大86400秒,谷歌中600秒,如果需要禁用緩存響應(yīng)返回-1即可。
Access-Control-Allow-Credentials
該頭信息是允許跨域請(qǐng)求中攜帶請(qǐng)求資源主要是cookie。只要在XMLHttpRequest對(duì)象中設(shè)置withCredentials=true同時(shí)Access-Control-Allow-Origin為當(dāng)前請(qǐng)求的域名,Access-Control-Allow-Credentials為true(字符串)即可攜帶資源請(qǐng)求。
Access-Control-Allow-Methods
該頭信息是允許跨域請(qǐng)求類型集,可以設(shè)置為指定的請(qǐng)求類型如:GET、POST、PUT、DELETE等,也可以設(shè)置為*通配符允許所有請(qǐng)求類型,默認(rèn)不設(shè)置即允許所有請(qǐng)求。該頭信息僅在預(yù)檢請(qǐng)求中有效,標(biāo)準(zhǔn)要求是當(dāng)發(fā)送OPTIONS請(qǐng)求時(shí)如果響應(yīng)中允許當(dāng)前指定請(qǐng)求類型時(shí)會(huì)自動(dòng)再發(fā)起一次指定的請(qǐng)求類型請(qǐng)求并對(duì)XMLHttpRequest對(duì)象作出回調(diào),目前各瀏覽器實(shí)現(xiàn)并不統(tǒng)一,有的瀏覽器此參數(shù)無(wú)效。
Access-Control-Allow-Headers
該頭信息用于開放額外發(fā)送給服務(wù)器的頭信息,默認(rèn)必定允許Accept、Accept-Language、Content-Language、Content-Type等常規(guī)允許頭信息設(shè)置,當(dāng)指定其它頭信息時(shí)瀏覽器啟動(dòng)預(yù)檢請(qǐng)求詢問服務(wù)器是否允許額外的這些頭信息設(shè)置,如果允許則再發(fā)送常規(guī)請(qǐng)求。開放的頭信息多個(gè)以逗號(hào)分開也可以使用通配符*(通配符有兼容問題)。如果頭信息不能匹配允許則請(qǐng)求終止不再發(fā)起常規(guī)請(qǐng)求并且XMLHttpRequest獲取響應(yīng)失敗代碼無(wú)法獲取服務(wù)器的響應(yīng)內(nèi)容(有兼容性問題部分瀏覽器還是可以獲取服務(wù)器響應(yīng)內(nèi)容)。
跨域禁止修改請(qǐng)求頭信息
這些請(qǐng)求頭信息在跨域請(qǐng)求時(shí)瀏覽器禁止代碼修改。在非跨域請(qǐng)求則允許修改。
Origin
標(biāo)記請(qǐng)求來源站點(diǎn)。
Access-Control-Request-Method
用于通知服務(wù)器真實(shí)的請(qǐng)求類型。
Access-Control-Request-Headers
用于通知服務(wù)器請(qǐng)求頭字段集,多個(gè)以逗號(hào)分開或使用通配符*
兼容性
跨域請(qǐng)求是新開放的特性在兼容性方面差異比較多,一般推薦使用常規(guī)請(qǐng)求會(huì)更理想,使用預(yù)檢模式下很多代碼或服務(wù)器均未對(duì)OPTIONS請(qǐng)求類型提供支持導(dǎo)致請(qǐng)求失敗。對(duì)于瀏覽器內(nèi)核兼容性可查看:https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#Browser_compatibility
WebSocket
WebSocket是web引入的全新技術(shù),讓web端也能實(shí)現(xiàn)長(zhǎng)連接,目前兼容性?https://developer.mozilla.org/zh-CN/docs/Web/API/WebSocket#%E6%B5%8F%E8%A7%88%E5%99%A8%E5%85%BC%E5%AE%B9%E6%80%A7?。websocket允許跨域連接并且不需要額外處理,因?yàn)槭情L(zhǎng)連接,所以web服務(wù)器需要額外調(diào)整為長(zhǎng)連接才能與終端通信。websocket連接操作簡(jiǎn)單,但服務(wù)器端需要轉(zhuǎn)換處理方式,一般應(yīng)用與游戲、直播類項(xiàng)目較多。
兼容性
WebSocket請(qǐng)求是專門為H5設(shè)計(jì)的,目前支付H5的瀏覽器均支持。在部分瀏覽器中https與http頁(yè)面中使用ws與wss有安全限制,要求https只能連接wss,而http的可以使用ws和wss。
一般在https頁(yè)面中最好使用wss協(xié)議連接,如果服務(wù)端不支持wss可以通過nginx進(jìn)行轉(zhuǎn)發(fā)把ws改為wss。
插件
增加插件可以擴(kuò)展web功能。插件不受瀏覽器過多的限制,在跨域請(qǐng)求中可以很好的發(fā)輝。缺點(diǎn)是插件的開發(fā)形式不統(tǒng)一,兼容性也不一樣,目前比較多的是flash,但flash自身的問題已經(jīng)將慢慢進(jìn)入歷史舞臺(tái)了。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。