iOS 防 DNS 汙染方案調研 --- 302等 URL 重定向業務場景
概述
302等 URL 重定向業務場景需要解決的問題:
302 等重定向狀態碼,如何正確執行跳轉邏輯,要求跳轉後,依然需要執行 IP 直連邏輯,多次 302,也能覆蓋到。
302等 URL 重定向業務場景問題主要集中在 POST 請求上,解決方案的方向大致有幾種:
- 將請求方式統一替換為 GET
- 解決 POST 請求時的重定向問題
將 URL 統一替換為 GET,這種方案在客戶端這邊是成本最低的,如果團隊中達成一致是最好的。不過限製也是顯而易見的。那麼我們就著重討論下如何解決 POST 請求時的重定向問題。
POST 請求的重定向問題
對於 GET 請求,重定向問題較為簡單,我們著重討論下 POST 請求的重定向問題,看下不同狀態碼下的響應方式。
下麵介紹下重定向的類型以及解釋:
重定向的類型 | 對應協議 | 解釋 |
---|---|---|
300 Multiple Choices | HTTP 1.0 | 可選重定向,表示客戶請求的資源已經被轉向到另外的地址了,但是沒有說明是否是永久重定向還是臨時重定向。 |
301 Moved Permancently | HTTP 1.0 | 永久重定向,同上,但是這個狀態會告知客戶請求的資源已經永久性的存在在新的重定向的 URL 上。 |
302 Moved Temporarily | HTTP 1.0 | 臨時重定向,在 HTTP1.1 中狀態描述是 Found,這個和 300 一樣,但是說明請求的資源臨時被轉移到新的 URL 上,在以後可能會再次變動或者此 URL 會正常請求客戶的連接。 |
303 See Other | HTTP 1.1 | 類似於 301/302,不同之處在於,如果原來的請求是 POST,Location 頭指定的重定向目標文檔應該通過 GET 提取(HTTP 1.1新)。 |
304 Not Modified | HTTP 1.0 | 並不真的是重定向 - 它用來響應條件 GET 請求,避免下載已經存在於瀏覽器緩存中的數據。 |
305 Use Proxy | HTTP 1.0 | 客戶請求的文檔應該通過 Location 頭所指明的代理服務器提取(HTTP 1.1新)。 |
306 | HTTP 1.0 | 已廢棄,不再使用 |
307 Temporary Redirect | HTTP 1.1 | 和302(Found)相同。許多瀏覽器會錯誤地響應 302 應答進行重定向,即使原來的請求是 POST,即使它實際上隻能在 POST 請求的應答是 303 時 才能重定向。由於這個原因,HTTP 1.1新增了 307,以便更加清楚地區分幾個狀態代碼:當出現 303 應答時,瀏覽器可以跟隨重定向的 GET 和 POST 請求;如果是 307 應答,則瀏覽器隻能跟隨對 GET 請求的重定向。(HTTP 1.1新) |
因為常見的重定向為 301、302、303 307,所以下麵重點說說這幾種重定向的處理方法。
HTTP1.0 文檔中的 302(或301) 狀態碼,原則上是要被廢棄的,它在 HTTP1.1 被細分為了 303 和 307。不過 303 和 307 應用並不廣泛,現在很多公司對 302(或301) 處理實際上是 303。
總結起來就是:
協議 | 狀態碼 | 協議規定 | 實際情況 |
---|---|---|---|
HTTP1.0 | 302(或301) | 不建議使用 | 仍在大麵積使用 |
HTTP1.1 | 303 + 307 | 舊有302(或301)被細分,並建議使用的新的狀態碼 | 應用麵積較小 |
這些新舊協議的主要差別集中在 POST 請求的重定向處理上:
對於301、302的location中包含的重定向url,如果請求method不是GET或者HEAD,那麼瀏覽器是禁止自動重定向的,除非得到用戶的確認,因為POST、PUT等請求是非冥等的(也就是再次請求時服務器的資源可能已經發生了變化)
另外注意307這種情況,表示的是 POST 不自動重定向為 GET ,需要詢問訪問當前 URL 的用戶,是否需要重定向,進行手動重定向。
目前瀏覽器大都還把302當作303處理了(注意,303是HTTP1.1才加進來的,其實從HTTP1.0進化到HTTP1.1,瀏覽器什麼都沒動),它們獲取到 HTTP 響應報文頭部的 Location 字段信息,並發起一個 GET 請求。
我們可以根據業務需要,對不同的狀態碼做處理,比如可以對303狀態碼做如下處理,
- location 中包含重定向 URL 就重定向
- 如果是 POST 請求修改為 GET 請求,並清空 body。
- 清空 host 信息
- 重新發送網絡請求
代碼示例:
NSString *location = self.response.headerFields[@"Location"];
if (location && location.length > 0) {
NSURL *url = [[NSURL alloc] initWithString:location];
NSMutableURLRequest *mRequest = [self.swizzleRequest mutableCopy];
mRequest.URL = url;
if ([[self.swizzleRequest.HTTPMethod lowercaseString] isEqualToString:@"post"]) {
// POST重定向為GET
mRequest.HTTPMethod = @"GET";
mRequest.HTTPBody = nil;
}
[mRequest setValue:nil forHTTPHeaderField:@"host"];
Cookie 場景重定向問題
之前提到的 Cookie 方案無法解決iOS11之前係統的 302 請求的 Cookie 問題,比如,第一個請求是 https://www.a.com ,我們通過在 request header 裏帶上 Cookie 解決該請求的 Cookie 問題,接著頁麵302跳轉到 https://www.b.com ,這個時候 https://www.b.com 這個請求就可能因為沒有攜帶 cookie 而無法訪問。當然,由於每一次頁麵跳轉前都會調用回調函數:
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler;
可以在該回調函數裏攔截302請求,copy request,在 request header 中帶上 cookie 並重新 loadRequest。不過這種方法依然解決不了頁麵 iframe 跨域請求的 Cookie 問題,畢竟-[WKWebView loadRequest:]隻適合加載 mainFrame 請求。
如果通過之前篇幅裏提到的 iOS11 的新 API 進行處理,也就不會有該問題。
相關的文章:
補充說明:
概念 | 解釋 | 舉例 |
---|---|---|
host | 可以是 IP 也可以是 FQDN。 | www.xxx.com 或 1.1.1.1 |
FQDN | fully qualified domain name,由主機名和域名兩部分組成 | www.xxx.com |
域名 | 域名分為全稱和簡稱,全稱就是FQDN、簡稱就是 FQDN 不包括主機名的部分 | 比如:xxx.com ,也就是www.xxx.com 這個 FQDN 中,www 是主機名,xxx.com 是域名。 |
文中部分提到的域名,如果沒有特殊說明均指的是 FQDN。
最後更新:2017-09-13 14:32:57