跨域與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,問題至此解決。
跨域與nginx的underscores_in_headers on