記錄我開發工作中遇到HTTP跨域和OPTION請求的一個坑
我透過這篇文章把今天工作中遇到的HTTP跨域和OPTION請求的一個坑記錄下來。
場景是我需要在部署在域名a的Web應用裡用JavaScript去消費一個部署在域名b的伺服器上的服務。域名b上的服務也是我開發的,因此我將域名a加到了該服務的HTTP響應結構的標頭檔案裡,這樣就允許了域名a上的JavaScript程式碼用AJAX訪問域名b的服務。
域名b上的服務是一個Servlet,允許域名a跨域訪問的程式碼就一行:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {// 做業務邏輯 response.setHeader("Access-Control-Allow-Origin", "域名a"); }
我在域名a的Web應用裡用AJAX發起服務請求:
執行後,發現並沒有顯示200的彈出視窗。
錯誤訊息:Request header field Authorization is not allowed by Access-Control-Allow-Headers in preflight response.
觀察Chrome開發者工具,發現其實域名b的服務已經成功執行了,確實返回了200的Status code,
而且我已經從Chrome開發者工具裡觀察到瀏覽器已經成功接到域名b傳送回來的請求了。
那這個錯誤是什麼鬼呢?根據錯誤訊息“Request header field Authorization is not allowed by Access-Control-Allow-Headers in preflight response” Google了一下,發現一些朋友遇到同樣的問題:
-
如何解決出現AXIOS的Request header field Content-Type is not allowed by Access-Control-Allow-Headers in preflight response.
網頁地址: 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; }
但我試過,在我的場景下還是不工作,因為我的例子裡,伺服器已經針對OPTIONS請求返回HTTP 200的狀態碼了。
2. 這個Stackoverflow的帖子裡,很多朋友都提供了自己的解決方案。
我一一試過,在我的場景裡都不能工作。
於是我查詢了Mozilla的一篇文件: HTTP訪問控制(CORS)
https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS
裡面談到了,在某些情況下,瀏覽器在發起“需要預檢的請求”之前,必須首先發起一個“預檢請求(Preflight)”到伺服器,以探測伺服器是否允許這個實際請求。"預檢請求"機制的使用,是為了避免跨域請求對伺服器的使用者資料產生未預期的影響。
那麼哪些請求算作“需要預檢的請求”呢?Mozilla的這篇文件定義得很清楚:
當請求滿足下述任一條件時,即應首先傳送預檢請求:
-
使用了下面任一 HTTP 方法:
-
PUT
-
DELETE
-
CONNECT
-
OPTIONS
-
TRACE
-
PATCH
-
人為設定了對 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
我再檢查我的程式碼,因為我在HTTP請求裡用xhr.setRequestHeader("Authorization", "使用者名稱:密碼的base64編碼" )新增了用於Basic Authentication的頭部,因此迫使該請求成為了“需要預檢的請求”,所以才有了OPTION請求的傳送。
現在我將其註釋掉:
這次遇到了401 Unauthorized錯誤了:
然而沒有預檢請求OPTION發出來了,請求型別變成了我期望的POST方式了。
但是現在就陷入了一個矛盾的境地:如果在請求頭部加上Basic Authentication的資訊,會遇到錯誤訊息“Request header field Authorization is not allowed by Access-Control-Allow-Headers in preflight response.”。如果去掉,雖然避免了預檢請求,但是又遇到401 Unauthorized錯誤了。
於是,我換了一種認證方式,終於成功實現了期望的跨域請求,在我域名a的前端應用裡列印出了來自於域名b的服務的響應。
我使用了form認證方式,這種方式不會造成該請求成為一個”需要預檢的請求“,所以最後跨域成功了。
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);
希望我的這個踩坑經歷對大家有點幫助。
要獲取更多Jerry的原創技術文章,請關注公眾號"汪子熙"或者掃描下面二維碼:
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/24475491/viewspace-2212876/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 跨域之OPTION請求【轉載】跨域
- Angular 記錄 - Rxjs 完整處理一個 Http 請求AngularJSHTTP
- 因為一個跨域請求,我差點丟了飯碗跨域
- 記錄一次解決服務請求的跨域問題跨域
- 前端http請求跨域問題解決前端HTTP跨域
- 跨域請求跨域
- 中止請求和超時 跨域的HTTP請求 認證方式 JSONP跨域HTTPJSON
- SpringBoot記錄HTTP請求日誌Spring BootHTTP
- CORS跨域請求CORS跨域
- vue跨域請求Vue跨域
- 基於 HTTP 請求攔截,快速解決跨域和代理 MockHTTP跨域Mock
- Vue3 跨域請求攜帶cookie操作並記錄cookieVue跨域Cookie
- 跨域請求中常見的幾個問題跨域
- 允許跨域請求跨域
- vue axios 請求跨域VueiOS跨域
- 記錄從0開發一個vue的富文字外掛過程以及遇到的坑Vue
- 記一次跨域post請求資料之preflight request跨域
- Cross-origin 跨域請求ROS跨域
- 同源政策與跨域請求跨域
- php 支援jsonp跨域請求PHPJSON跨域
- 跨域請求後端配置跨域後端
- NGINX如何配置跨域請求Nginx跨域
- Vue——介面請求支援跨域Vue跨域
- [Http] 跨站請求偽造(CSRF)HTTP
- 一個HTTP請求,把網站打裂開了HTTP網站
- ajax跨域請求之CORS的使用跨域CORS
- post請求帶來的option
- web 跨域請求安全問題Web跨域
- IE9 跨域請求相容IE9跨域
- golang開發:http請求redirect的問題GolangHTTP
- vue請求後端資料和跨域問題Vue後端跨域
- 簡單的實現jsonp跨域請求JSON跨域
- 求助,遇到個問題!jmeter 可以錄製公網的介面請求,但區域網的介面錄製不到JMeter
- 跨域是什麼?跨域請求資源有哪些方法?跨域
- Uncaught SyntaxError: Unexpected token : 開發遇到的跨域問題Error跨域
- 我的vue學習記錄1: 前端跨域代理配置Vue前端跨域
- 那些前端工作中遇到的坑(01)前端
- CROS跨域請求設定,偏重前端ROS跨域前端