Nginx緩衝引發的跨域慘案

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

1. 前言

貴金屬wap版直播間上線後,偶爾有使用者反饋,在進入wap直播間的時候,出現空白頁面,但是重新重新整理又可以正常顯示了。我們曾一度認為是網路請求異常或相容問題,直到開發PC版直播間,在進行調試中,同樣遇到了“白屏”問題,才引起了足夠重視,並進行了問題跟蹤與分析。現在跟大家分享一下,這種偶然現象出現的原因。

我們的直播間落地頁在fa.163.com 系統,而直播間內容,是通過 向直播間系統 qz.fa.163.com 發起Ajax請求擷取的。在出現“白屏”的時候,可以通過瀏覽器的調試視窗,可以看到出現下面的報錯:

2. 問題分析

從上述錯誤提示文案中可以看到,問題首先和 跨域 有關。

何為跨域

從字面上理解為“跨網域名稱”,
瀏覽器不能執行其他網站的指令碼,然而,跨域不僅僅局限於網域名稱這一項。只要協議、網域名稱、連接埠有任何一個不同,都被當作是不同的域。 這是由於>同源策略的限制,從一個域上載入的指令碼不允許訪問另外一個域的文件屬性。雖然在瀏覽器中,<script>、<img>、<iframe>、<link>等標籤都>可>以載入跨域資源,而不受同源限制,但瀏覽器會限制指令碼中發起的跨域請求。比如,使用 XMLHttpRequest 對象和Fetch發起 HTTP 要求就必須遵守同源策略。

同源策略/SOP(Same origin policy)是一種約定,它是瀏覽器最核心也最基本的安全功能,如果缺少了同源策略,瀏覽器很容易受到XSS、CSFR等攻擊。SOP要求兩個郵寄地址的協議、網域名稱、連接埠號碼必須相同,否則兩個地址的通訊將被瀏覽器視為不安全的,並被block下來。

舉個例子:從貴金屬主站 http://fa.163.com 發起請求訪問以下url:

解決跨域

在實際應用中有多種方式來解決跨域問題,相信在實踐中都會用到其中的某些方案:

1.JSONP (無狀態串連,不能獲悉串連狀態和錯誤事件,而且只能走GET的形式)

2.iframe形式

3.伺服器代理

頁面直接向同域的服務端發請求,服務端進行跨域處理或爬蟲後,再把資料返回給用戶端頁。

4.CORS

CORS(Cross-Origin Resource Sharing)跨域資源共用,定義了必須在訪問跨域資源時,瀏覽器與伺服器應該如何溝通。CORS背後的基本思想就>是使用自訂的HTTP頭部讓瀏覽器與伺服器進行溝通,從而決定請求或響應是應該成功還是失敗。目前,所有瀏覽器都支援該功能,IE瀏覽器不能低>於IE10。整個CORS通訊過程,都是瀏覽器自動完成,不需要使用者參與。對於開發人員來說,CORS通訊與同源的AJAX通訊沒有差別,代碼完全一樣。瀏>覽器一旦發現AJAX請求跨源,就會自動添加一些附加的頭資訊,有時還會多出一次附加的請求,但使用者不會有感覺。

CORS方式實現:

瀏覽器在發出CORS請求時會在頭資訊之中增加一個Origin欄位;

後端傳回碼中增加三個欄位

1
2
3
header(“Access-Control-Allow-Origin”:“”);           // 必選 允許所有來源訪問
header(“Access-Control-Allow-Credentials”:“true”); //可選 是否允許發送cookie
header(“Access-Control-Allow-Method”:“POST,GET”); //可選 允許訪問的方式

5.nginx反向 Proxy

nginx是一個高效能的web伺服器,常用作反向 Proxy伺服器。nginx作為反向 Proxy伺服器,就是把http請求轉寄到另一個或者一些伺服器上。通過把本地一個url首碼映射到要跨域訪問的web伺服器上,就可以。

為瞭解決跨域問題,我們選擇方案d , 在直播間的過濾器中,統一添加了如下代碼:

1
2
3
4
5
6
7
8
9
10
   @Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 加入回應標頭
String origin = request.getHeader("Origin");
if("http://fa.163.com".equals(origin) || "https://fa.163.com".equals(origin) ) {
response.addHeader("Access-Control-Allow-Origin", origin);
response.addHeader("Access-Control-Allow-Credentials", "true");
}
return true;
}

從錯誤提示文案中,我們還可以看到錯誤提示的關鍵點 “http://fa.163.com” that is not equal to the supplied origin. Origin ‘https://fa.163.com‘ is therefore not allowed access.
目前我們的系統同時支援http訪問和https訪問,但是為什麼使用 http訪問 ,返回的header中卻是 https 協議呢?
通過多次類比,確認出現問題的請求中,Request URL使用的協議和 response返回的headers中的 Access-Control-Allow-Origin 中的 協議確實不一致,且還有一個特性,X-Cached 為 HIT,如:

命中了緩衝的請求,出現了協議不一致?

突然想到,這個介面,我們配置了nginx 緩衝,那必然和nginx緩衝有關了。

Nginx 緩衝

Nginx (engine x) 是一個高效能的HTTP和反向 Proxy伺服器。
首先從原始伺服器(內部網路上的web伺服器)上擷取內容,然後把內容返回給使用者,同時,也會把內容儲存到Proxy 伺服器上一份,這樣日後再接收同樣的資訊請求時,他會把本機快取裡的內容直接發給使用者,以此減少後端web伺服器的壓力,提高響應速度。這其實就是快取服務器所實現的功能。如所示。

進入直播間後,首先需要查詢直播內容是否有更新,而這個介面用戶端會以5s間隔輪詢,為了減少tomcat的壓力,我們配置了nginx緩衝。配置如下:

其中:

proxy_cache_methods: 用來設定HTTP哪些方法會被緩衝,直播間介面配置了GET、HEAD、POST;proxy_cache_valid:    用來設定對不同HTTP狀態代碼的不同緩衝時間。直播間介面配置了對於 傳回值為200的狀態代碼,緩衝5秒;proxy_cache_min_uses: 用來設定多少次訪問後,應答值會被緩衝,配置為3次;proxy_cache_key:      設定Web緩衝的keyproxy_cache:          用來設定哪個緩衝區將被使用,並定義緩衝區的名稱

通過上述配置,我們可以看到 proxy_cache_key 配置中,只配置了host + uri + 參數,但沒有配置協議,所以無論用http訪問,還是https訪問,只要被緩衝後,返回的內容都是一樣的,而不會區分http或https。從而引起了跨域問題。
至此,問題分析完畢。

3. 問題解決

跟營運同學溝通後,通過修改nginx配置,將協議類型scheme加入到緩衝尋找的判斷參數中,配置如下。

問題得到瞭解決。

4. 總結

上述“慘案” ,是 跨域、nginx緩衝、http/https協議 這三種條件同時出現引發的。
如果不涉及跨域,混用 http/https協議 + nginx緩衝,其實也是沒有問題的。但是一旦出現了跨域使用,必須 在nginx 緩衝配置中,配置 scheme + host + uri + 參數。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.