摘要:我通過(guò)這篇文章把今天工作中遇到的跨域和請(qǐng)求的一個(gè)坑記錄下來(lái)。預(yù)檢請(qǐng)求機(jī)制的使用,是為了避免跨域請(qǐng)求對(duì)服務(wù)器的用戶數(shù)據(jù)產(chǎn)生未預(yù)期的影響。我使用了認(rèn)證方式,這種方式不會(huì)造成該請(qǐng)求成為一個(gè)需要預(yù)檢的請(qǐng)求,所以最后跨域成功了。
我通過(guò)這篇文章把今天工作中遇到的HTTP跨域和OPTION請(qǐng)求的一個(gè)坑記錄下來(lái)。
場(chǎng)景是我需要在部署在域名a的Web應(yīng)用里用JavaScript去消費(fèi)一個(gè)部署在域名b的服務(wù)器上的服務(wù)。域名b上的服務(wù)也是我開(kāi)發(fā)的,因此我將域名a加到了該服務(wù)的HTTP響應(yīng)結(jié)構(gòu)的頭文件里,這樣就允許了域名a上的JavaScript代碼用AJAX訪問(wèn)域名b的服務(wù)。
域名b上的服務(wù)是一個(gè)Servlet,允許域名a跨域訪問(wèn)的代碼就一行:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 做業(yè)務(wù)邏輯 response.setHeader("Access-Control-Allow-Origin", "域名a"); }
我在域名a的Web應(yīng)用里用AJAX發(fā)起服務(wù)請(qǐng)求:
執(zhí)行后,發(fā)現(xiàn)并沒(méi)有顯示200的彈出窗口。
錯(cuò)誤消息:Request header field Authorization is not allowed by Access-Control-Allow-Headers in preflight response.
觀察Chrome開(kāi)發(fā)者工具,發(fā)現(xiàn)其實(shí)域名b的服務(wù)已經(jīng)成功執(zhí)行了,確實(shí)返回了200的Status code,
而且我已經(jīng)從Chrome開(kāi)發(fā)者工具里觀察到瀏覽器已經(jīng)成功接到域名b發(fā)送回來(lái)的請(qǐng)求了。
那這個(gè)錯(cuò)誤是什么鬼呢?根據(jù)錯(cuò)誤消息“Request header field Authorization is not allowed by Access-Control-Allow-Headers in preflight response” Google了一下,發(fā)現(xiàn)一些朋友遇到同樣的問(wèn)題:
1.?如何解決出現(xiàn)AXIOS的Request header field Content-Type is not allowed by Access-Control-Allow-Headers in preflight response.
網(wǎng)頁(yè)地址: https://www.cnblogs.com/caimu...
這位朋友的解決方案:
response.setHeader("Access-Control-Allow-Origin", "*"); response.setHeader("Access-Control-Allow-Credentials", "true"); response.setHeader("Access-Control-Allow-Methods", "*"); response.setHeader("Access-Control-Allow-Headers", "Content-Type,Access-Token"); response.setHeader("Access-Control-Expose-Headers", "*"); if (request.getMethod().equals("OPTIONS")) { HttpUtil.setResponse(response, HttpStatus.OK.value(), null); return; }
但我試過(guò),在我的場(chǎng)景下還是不工作,因?yàn)槲业睦永?,服?wù)器已經(jīng)針對(duì)OPTIONS請(qǐng)求返回HTTP 200的狀態(tài)碼了。
2. 這個(gè)Stackoverflow的帖子里,很多朋友都提供了自己的解決方案。
https://stackoverflow.com/que...
我一一試過(guò),在我的場(chǎng)景里都不能工作。
于是我查詢了Mozilla的一篇文檔:HTTP訪問(wèn)控制(CORS)
https://developer.mozilla.org...
里面談到了,在某些情況下,瀏覽器在發(fā)起“需要預(yù)檢的請(qǐng)求”之前,必須首先發(fā)起一個(gè)“預(yù)檢請(qǐng)求(Preflight)”到服務(wù)器,以探測(cè)服務(wù)器是否允許這個(gè)實(shí)際請(qǐng)求。"預(yù)檢請(qǐng)求"機(jī)制的使用,是為了避免跨域請(qǐng)求對(duì)服務(wù)器的用戶數(shù)據(jù)產(chǎn)生未預(yù)期的影響。
那么哪些請(qǐng)求算作“需要預(yù)檢的請(qǐng)求”呢?Mozilla的這篇文檔定義得很清楚:
當(dāng)請(qǐng)求滿足下述任一條件時(shí),即應(yīng)首先發(fā)送預(yù)檢請(qǐng)求:
使用了下面任一 HTTP 方法:
PUT
DELETE
CONNECT
OPTIONS
TRACE
PATCH
人為設(shè)置了對(duì) CORS 安全的首部字段集合之外的其他首部字段。該集合為:
Accept
Accept-Language
Content-Language
Content-Type (but note the additional requirements below)
DPR
Downlink
Save-Data
Viewport-Width
Width
Content-Type 的值不屬于下列之一:
application/x-www-form-urlencoded
multipart/form-data
text/plain
我再檢查我的代碼,因?yàn)槲以贖TTP請(qǐng)求里用xhr.setRequestHeader("Authorization", "用戶名:密碼的base64編碼" )添加了用于Basic Authentication的頭部,因此迫使該請(qǐng)求成為了“需要預(yù)檢的請(qǐng)求”,所以才有了OPTION請(qǐng)求的發(fā)送。
現(xiàn)在我將其注釋掉:
這次遇到了401 Unauthorized錯(cuò)誤了:
然而沒(méi)有預(yù)檢請(qǐng)求OPTION發(fā)出來(lái)了,請(qǐng)求類型變成了我期望的POST方式了。
但是現(xiàn)在就陷入了一個(gè)矛盾的境地:如果在請(qǐng)求頭部加上Basic Authentication的信息,會(huì)遇到錯(cuò)誤消息“Request header field Authorization is not allowed by Access-Control-Allow-Headers in preflight response.”。如果去掉,雖然避免了預(yù)檢請(qǐng)求,但是又遇到401 Unauthorized錯(cuò)誤了。
于是,我換了一種認(rèn)證方式,終于成功實(shí)現(xiàn)了期望的跨域請(qǐng)求,在我域名a的前端應(yīng)用里打印出了來(lái)自于域名b的服務(wù)的響應(yīng)。
我使用了form認(rèn)證方式,這種方式不會(huì)造成該請(qǐng)求成為一個(gè)”需要預(yù)檢的請(qǐng)求“,所以最后跨域成功了。
var formData = new FormData(); formData.append("sap-client", "001"); formData.append("sap-user", "用戶名"); formData.append("sap-password", "用戶密碼"); var request = new XMLHttpRequest(); request.open("POST", "域名b的url",false); request.send(formData); alert("response: " + request.responseText);
希望我的這個(gè)踩坑經(jīng)歷對(duì)大家有點(diǎn)幫助。
要獲取更多Jerry的原創(chuàng)技術(shù)文章,請(qǐng)關(guān)注公眾號(hào)"汪子熙"或者掃描下面二維碼:
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/98561.html
摘要:發(fā)送到后臺(tái)的數(shù)據(jù)見(jiàn)下圖這種方式會(huì)以鍵值對(duì)的形式通過(guò)分隔符鏈接,以字符串給后臺(tái),可以傳輸文件,也可以傳輸普通數(shù)據(jù)??缬蚩缬騿?wèn)題的根本問(wèn)題就是同源策略,旨在防止網(wǎng)站被攻擊,這里不做贅述??蛻舳?,以為例服務(wù)端允許跨域的請(qǐng)求的方法。 HTTP基礎(chǔ) 其實(shí)很多面試問(wèn)HTTP的3次握手,4次揮手,我覺(jué)得價(jià)值不大,可以幫助你理解HTTP的原理,死背硬記的對(duì)于你開(kāi)發(fā)沒(méi)有作用,而是去理解它就行。前端只關(guān)心...
摘要:實(shí)際使用時(shí),由于向提交的長(zhǎng)度限制在字符,超過(guò)了則被瀏覽器拒絕,因此不采用。前端發(fā)起跨域請(qǐng)求就是正常的請(qǐng)求即可。 問(wèn)題背景瀏覽器從一個(gè)域名的網(wǎng)頁(yè)去請(qǐng)求另一個(gè)域名的資源時(shí),域名、端口、協(xié)議任一不同,都是跨域 在前后端開(kāi)發(fā)過(guò)程經(jīng)常會(huì)遇到跨域問(wèn)題。網(wǎng)上也都有解決方案。 寫(xiě)這篇文章時(shí),我們碰到的一個(gè)場(chǎng)景是:要給s系統(tǒng)做一個(gè)擴(kuò)展,前端的html、js放在s系統(tǒng)里,后端需要做一個(gè)單獨(dú)的站點(diǎn)N.B....
摘要:今天這篇文章,我們會(huì)介紹幾種常見(jiàn)的方法和其中存在的問(wèn)題,并提出如何基于請(qǐng)求攔截,快速解決跨域和代理問(wèn)題的方案。因?yàn)闆](méi)有修改該請(qǐng)求,只是延遲發(fā)送,這樣就保持了原請(qǐng)求與業(yè)務(wù)服務(wù)器之間的所有鑒權(quán)等相關(guān)信息,由此解決了跨域訪問(wèn)無(wú)法攜帶的問(wèn)題。 近幾年,隨著 Web 開(kāi)發(fā)逐漸成熟,前后端分離的架構(gòu)設(shè)計(jì)越來(lái)越被眾多開(kāi)發(fā)者認(rèn)可,使得前端和后端可以專注各自的職能,降低溝通成本,提高開(kāi)發(fā)效率。 在前后端...
摘要:這個(gè)坑就是要注意回調(diào)結(jié)束要返回成功的響應(yīng)這幾天做微信支付暫時(shí)遇到的問(wèn)題就這么多,只能說(shuō)注意細(xì)節(jié)吧,爬過(guò)的坑記錄下來(lái)以后遇到就懂處理了。 前言 其實(shí)任何接口開(kāi)發(fā)只要按照給出來(lái)的接口文檔和例子開(kāi)發(fā)基本上不會(huì)有太大問(wèn)題的,一些問(wèn)題都是出在雜七雜八的小細(xì)節(jié)上,現(xiàn)在分享一下微信支付開(kāi)發(fā)中自己遇到的小細(xì)節(jié)。按照文檔做完開(kāi)發(fā)前配置,比如JS安全域名配置、網(wǎng)頁(yè)授權(quán)域名、公眾號(hào)授權(quán)目錄等等... 坑一:...
摘要:前言最近在業(yè)務(wù)代碼中深受跨域問(wèn)題困擾,因此特別寫(xiě)一篇博客來(lái)記錄一下自己對(duì)跨域的理解以及使用到的參考資料。內(nèi)嵌式跨域通常也是允許的。而我使用時(shí)因?yàn)檫@個(gè)響應(yīng)報(bào)文最后被認(rèn)為是跨域問(wèn)題,無(wú)法從中獲得的狀態(tài)碼。它代表服務(wù)器支持跨域時(shí)攜帶認(rèn)證信息。 前言 最近在業(yè)務(wù)代碼中深受跨域問(wèn)題困擾,因此特別寫(xiě)一篇博客來(lái)記錄一下自己對(duì)跨域的理解以及使用到的參考資料。本文的項(xiàng)目背景基于vue+vuex+axio...
閱讀 1956·2021-11-23 09:51
閱讀 1604·2021-11-19 09:40
閱讀 3267·2021-11-11 11:01
閱讀 1217·2021-09-27 13:34
閱讀 1910·2021-09-22 15:56
閱讀 2193·2019-08-30 15:52
閱讀 1130·2019-08-30 14:13
閱讀 3544·2019-08-30 14:10