记录我开发工作中遇到HTTP跨域和OPTION请求的一个坑
我通過這篇文章把今天工作中遇到的HTTP跨域和OPTION請(qǐng)求的一個(gè)坑記錄下來。
場(chǎng)景是我需要在部署在域名a的Web應(yīng)用里用JavaScript去消費(fèi)一個(gè)部署在域名b的服務(wù)器上的服務(wù)。域名b上的服務(wù)也是我開發(fā)的,因此我將域名a加到了該服務(wù)的HTTP響應(yīng)結(jié)構(gòu)的頭文件里,這樣就允許了域名a上的JavaScript代碼用AJAX訪問域名b的服務(wù)。
域名b上的服務(wù)是一個(gè)Servlet,允許域名a跨域訪問的代碼就一行:
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)并沒有顯示200的彈出窗口。
錯(cuò)誤消息:Request header field Authorization is not allowed by Access-Control-Allow-Headers in preflight response.
觀察Chrome開發(fā)者工具,發(fā)現(xiàn)其實(shí)域名b的服務(wù)已經(jīng)成功執(zhí)行了,確實(shí)返回了200的Status code,
而且我已經(jīng)從Chrome開發(fā)者工具里觀察到瀏覽器已經(jīng)成功接到域名b發(fā)送回來的請(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)一些朋友遇到同樣的問題:
1.?如何解決出現(xiàn)AXIOS的Request header field Content-Type is not allowed by Access-Control-Allow-Headers in preflight response.
網(wǎng)頁地址: https://www.cnblogs.com/caimuqing/p/6733405.html
這位朋友的解決方案:
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;}但我試過,在我的場(chǎng)景下還是不工作,因?yàn)槲业睦永?#xff0c;服務(wù)器已經(jīng)針對(duì)OPTIONS請(qǐng)求返回HTTP 200的狀態(tài)碼了。
2. 這個(gè)Stackoverflow的帖子里,很多朋友都提供了自己的解決方案。
https://stackoverflow.com/questions/42061727/cors-error-request-header-field-authorization-is-not-allowed-by-access-control/42061962
我一一試過,在我的場(chǎng)景里都不能工作。
于是我查詢了Mozilla的一篇文檔:HTTP訪問控制(CORS)
https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS
里面談到了,在某些情況下,瀏覽器在發(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ò)誤了:
然而沒有預(yù)檢請(qǐng)求OPTION發(fā)出來了,請(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)用里打印出了來自于域名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)"汪子熙"或者掃描下面二維碼:
總結(jié)
以上是生活随笔為你收集整理的记录我开发工作中遇到HTTP跨域和OPTION请求的一个坑的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SAP成都研究院姚瑶:软件质量保证工作的
- 下一篇: 【总结整理】Edraw Max亿图图示软