解決IOS12複雜跨域兼容問題的方案與思路

一. 故事的起因

對於一個沒有其它領域開發背景的APP開發人員來說,“跨域資源訪問”可能真的不屬於我們需要認真關心的問題。就原生開發來說,主流的接口開發模式大多數都轉變成無狀態的接口請求方式,一方面可以真正迎合APP在開發過程中的簡單適用性。對於服務端來說,在後期的優化及擴展實現上更簡單靈活。無需要像網頁開發一樣,用臨時隱藏cookit字段的方式實現用戶身份的辨認(Session)。APP在進行接口請求時,都可以在HTTP頭或者body中附帶個人身體識別碼(token)等信息給到接口進行身份識別。所以,就這麼簡單粗暴。

但是,儘管這樣,我們做這行,多知道點東西還是沒壞處的,說不定哪天就用上了。

於是,這麼一天就到了。也就是前段時間,我們的專車項目有一部分邊緣業務是以混合開發的模式嵌入了WKWebview進行H5頁面的展示。對於我們做APP的人來說,這是再簡單不過的事情了。

開發好之後給到測試人員進行測試的時候,我們發現很多系統上都沒測到H5在WKWebview運行的問題,唯獨在IOS12系統的手機上,有些流程不能走通。在排除了各方面問題後,一班人感覺束手無策。

這時候,web前端懷疑是服務端接口的問題,服務端接口在懷疑是我們APP的問題。對於很多APP開發人員來說,WKWebview的使用也就那麼回事了,想做錯都比較難,於是就陷入僵局。

因爲打車項目只是我們團隊開發的衆多項目中比較小的一個,我就安排了一兩個人去做項目的更新迭代,到時下午開小組會議的時候我才得知問題的存在。在初步得知情況後,把問題指向了 “是否WKWebview在IOS12系統上存在寬容度的差異” 的問題進行了思考。

於是我一方面與前端開發人員進行了問題的溝通,詢問其web處理流程後,可以初步確定是由於 WKWebview在IOS12系統中,進行復雜跨域處理時,跨域流程無法正常進行 的問題。

二. 什麼是跨域資源訪問

因爲是web端開發的相關知識,爲了更好理解下面的內容,這裏我就簡單總結帶過一下。

說到跨域資源訪問 就不得不說跨域資源保護

跨域資源保護是瀏覽器提供的一種最爲基本的安全保護策略,當前域上的腳本想訪問其它域上的資源都要在該策略下進行。

當前,web開發採用的前後端分離的開發方式已經是比較普遍的了。在該項目中,H5面頁在完成加載後,會以異步請求的方式對頁面中的數據進行異步加載及顯示。在進行異步請求的時候,調用了另一個項目的接口進行數據加載。協議 + 域名 + 端口 中基中一者與當前資源不一致的時候,就構成了 跨域資源訪問

三. CORS跨域安全標準

解決web端的跨域問題的方案有幾個,CORS是業內較爲常用的標準,爲大多數常用的瀏覽器所支持。

CORS的實現方式或者處理方式上,可以分爲:簡單跨域處理 和 *複雜跨域處理

下面就簡單帶過一下:

1. 簡單跨域請求

我就不一一列出什麼纔是屬於“簡單跨域”的條件了,簡單來說就是在一般簡單的標準HTTP請求過程中,如果瀏覽器識別到你請求的資源與當前的“域”不一致的時候,會自動在HTTP頭添加Origin: www.xxx.com信息給到服務端接口進行簡單跨域請求的處理.

服務端接口在收到你的請求時,對Origin信息進行獲取,並進行相關判斷後。對該請求表示接受時,在返回的清求中附帶Access-Control-Allow-Origin 的參數放到HTTP頭中。

瀏覽器在接收到簡單跨域請求返回時,判斷Access-Control-Allow-Origin是否有正確返回 (一般的值可以爲 * ,或者返回訪問域)。如果沒有,將終止流程繼續進行。(當然,這裏還有其它值的返回,這裏就不一一說明了)

2. 複雜跨域請求

複雜跨域的條件我就不一一說了。在我們當前項目中,由於H5在進行跨域異步請求時,在HTTP請求中加入了幾個自定義的HTTP頭

瀏覽器在偵測到複雜跨域請求時,會先發一個Option請求到對應的服務端,請求跨域的允許。

服務端在接收到Option請求時,會與上面的“簡單跨域請求”一樣,返回幾個頭信息。

瀏覽器在接收到Option請求返回的結果進行判斷是否繼續後續正式請求的發送。

四. 發現問題的步驟

1. 對不同硬件平臺不同系統進行測試

得出結論:與硬件平臺無關,與軟件系統有關。問題只出現在IOS12的系統上

2.確定跨域類型,及接口端的實現

通過對H5腳本進行分析,得出跨域類型爲:複雜跨域 也可以說是 非簡單跨域

通過對整個過程進行抓包處理,得出結論:服務端在進行複雜跨域的預處理上,初步實現對相關頭信息的返回。但在IOS12系統的WKWebview上,接口接收到Option複雜跨域請求,正常返回後,沒有繼續提交正式的Post請求。

五. 解決問題的步驟

1. 能否在原生開發層面解決問題:

經過對WKWebview進行所有API的查找,沒有發現相關設置。
經過基項目相關配置進行查閱,也沒有相關的設置開關。

2. 能否通過外部條件解決問題:

問題的癥結集中在在IOS12系統的WKWebview上,接口接收到Option複雜跨域請求,正常返回後,沒有繼續提交正式的Post請求這個問題上。而由上面可以初步排除通過原生的方式修改代碼實現流程的貫通的辦法。

於是我開始懷疑是否在IOS12系統上的WKWebview,存在對Option請求返回數據的寬容度與其它系統存在區別?是否通過對返回數據的值進行修改,可以觸發流程的貫通?

爲了印證我的猜測,我做了如下的測試,最終把問題解決:

1. Access-Control-Allow-Origin

這個值的作非常重要,瀏覽器在接收到跨域預檢返回信息中,首先判斷這個值是否有正常返回,進而進行下一步的操作。

我們對Origin的值進行了多種返回值的償試:
*值: 沒有效果
返回請求域的值:比如api.lemacar.com,還是沒有效果

2. Access-Control-Allow-Credentials

這個返回值爲bool數據類型,用於表示,在進行Option請示的發送時,是否把當前瀏覽器中存在對應該域的Cookie信息一起發送到服務端進行驗證處理。

個人感覺這個值對於處理問題的作用不大,於是在償試過true false後,和預想中的一樣, 沒有效果。

3. Access-Control-Expose-Headers

在進行值的償試過程中,把這個值放到了最後,因爲自己義頭信息有好幾個,於是我們就從簡單的值開始入手。

當我們發現對上面兩個值進行返回值的修改後沒有效果,於是發起了一陣驚歎 “難道真的要對所有自定義頭進行返回嗎?”,因爲我們一直用的是通配符*作爲Headers的值返回。

於是在一番折騰後,流程真的通了

六. 結論

在IOS12系統中,WKWebview在遇到複雜跨域請求時,也會先自動發送Option請求進行預檢,但在返回的HTTP頭的Access-Control-Expose-Headers字段中,不能用是通配符*作爲值返回,一定要明確反回你在下一部操作中的自定義頭。

同時,還可以明確一點:在IOS12系統中,WKWebview在遇到簡單跨域請求時的流程是沒有問題的。所以當時前端的服務端在遇到這個問題時,就把複雜跨域請求改成了簡單跨域請求。當然這種解決問題的辦法不是長久之計。

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