跨域異常與nginx的underscores_in_headers on

原文地址

最近上線了一個代理系統,通過nginx代理第三方應用來打通不同區域之間的防火牆限制,從而實現訪問策略的一些業務。

期間在系統代理客戶某個應用的時候遇到了跨域問題,由於自己的慣性思維的邏輯,導致花費了整整一天的時間才解決,而且還是同事協助完成,所以特此記錄,用以警醒!

 

場景再現

 客戶環境:

    應用服務器:nginx部署實現負載均衡

    應用涉及的ws服務器:nginx部署實現負載均衡

本地環境:

    代理系統:通過nginx實現代理

具體操作:

    在代理系統分別添加客戶應用與ws服務器,通過nginx.conf配置了兩個server塊來實現。

    結果在瀏覽器訪問客戶應用服務器的時候,客戶應用通過ajax發送的ws請求全都拋出跨域異常(XMLHttpRequest cannot load ''. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin '' is therefore not allowed access.)。

 

 

關於跨域

 

什麼是跨域


跨域訪問是瀏覽器的一種限制, 原因是爲了安全問題;

瀏覽器通過同源策略來實現跨域限制,同源策略是指域名、協議、端口相同纔是同一個源;

比如a頁面想獲取b頁面資源,如果a、b頁面的協議、域名、端口、子域名不同,所進行的訪問行動都是跨域的。

 

場景再現


在遇到跨域問題當時第一反應就是同源策略,想到代理系統配置兩個server塊來代理,而兩個server_name的域名就產生了同源問題,

所以圍繞着怎麼把客戶應用與ws服務器通過一個server塊來實現花費了大把時間,關鍵在於客戶ajax請求的ws是全路徑,如http://aaa:8080/ws,這在本地發出ajax請求是直接發送給aaa域名的,而客戶應用域名又爲http://xxx:8080/app,

除非客戶的ws請求改成相對路徑,如/ws,否則就會出現同源問題;

用戶是不可控的,所以一個server塊實現的方案根本不可行!

 

糾結半天后退而求其次,想通過在代理的ws服務器設置http頭(Access-Control-Allow-Origin)來解決當前客戶需求,這樣不足之處也是因爲不能控制用戶是否已經配置了該http頭,如果客戶添加了,那麼我們再次設置的話是有問題的,經過測試,用戶的ws服務器確實設置了Access-Control-Allow-Origin,所以最終會拋出異常(XMLHttpRequestcannot load. The 'Access-Control-Allow-Origin' header contains multiple values'*, *', but only one is allowed. Origin '' is therefore notallowed access);

在這裏設置Access-Control-Allow-Origin花費了半天時間,因爲沒設置就會出現最初的跨域異常,設置了相當於兩層代理都添加了這個http頭信息而導致multiple values'*。

 

CORS協議


 

什麼是cors:

CORS是一個W3C標準,全稱是”跨域資源共享”(Cross-originresource sharing)。

它允許瀏覽器向跨源服務器,發出XMLHttpRequest請求,從而克服了AJAX只能同源使用的限制。

整個CORS通信過程,都是瀏覽器自動完成,不需要用戶參與。對於開發者來說,CORS通信與同源的AJAX通信沒有差別,代碼完全一樣。瀏覽器一旦發現AJAX請求跨源,就會自動添加一些附加的頭信息,有時還會多出一次附加的請求,但用戶不會有感覺。

因此,實現CORS通信的關鍵是服務器。只要服務器實現了CORS接口 ,就可以跨源通信。

在服務器響應客戶端的時候,帶上Access-Control-Allow-Origin頭信息(這個header就是讓服務器支持CORS的)。

 

cors常見的header:

Access-Control-Allow-Origin:http://kbiao.me   表明它允許”http://kbiao.me“發起跨域請求
Access-Control-Max-Age:3628800  表明在3628800秒內,不需要再發送預檢驗請求,可以緩存該結果
Access-Control-Allow-Methods:GET,PUT, DELETE  表明它允許GET、PUT、DELETE的外域請求 
Access-Control-Allow-Headers:content-type 表明它允許跨域請求包含content-type頭

 

解決方法


 jsonp 需要目標服務器配合一個callback函數。

iframe 需要目標服務器響應window.name。

CORS 需要服務器設置header :Access-Control-Allow-Origin。

nginx反向代理 不用目標服務器配合,支持所有瀏覽器。

建議使用nginx。

 

 

underscores_in_headers on 

 

介紹


nginx代理默認會把header中參數的 "_" 下劃線去掉,所以後臺服務器後就獲取不到帶"_"線的參數名。

underscores_in_headers on; #該屬性默認爲off,表示如果header name中包含下劃線,則忽略掉。

 

 場景再現


兩層代理產生的異常後,發現根本就不是跨域問題,最後全面盤查才發現ws的請求雖然都是200,不過響應的數據都是空的,

原因是ws請求時沒有攜帶參數,而真相就在這裏,客戶請求的參數包含了"_",nginx默認忽略。

把之前的猜測推倒重來,在代理的兩個server塊加上underscores_in_headers on,問題至此解決。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章