現象:
通過抓包看到在部分客戶端上跨域的非簡單請求只發送一個預檢的OPTIONS請求,之後的真實請求並沒有發送。
出現問題的環境:
部分IOS低版本系統。
windows系統微信內必現(2020-04-29)。
分析
通過上面條件OPTIONS請求發送成功,但是實際請求沒有發送,可以推斷出是服務端相關HTTP頭沒有設置正確,導致客戶端認爲服務端不允許當前源上的web應用跨域訪問該資源,所以後面真正的請求沒有發送(fetch的表現爲status: 0)。
服務端響應頭如下:
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: *
Access-Control-Allow-Methods: *
正常來說不存在問題,因爲設置的值也都是合法的,並且在絕大部分客戶端上都是正常的。
CORS定義:
CORS跨域資源共享,是通過額外的HTTP頭來告訴瀏覽器,源上的web應用被允許訪問來自不同源服務器的指定資源。
這裏額外的HTTP頭值得注意,可以看出來CORS在不同的瀏覽器上可能是有兼容性問題。
方案
一開始的猜想是HTTP請求的method的值OPTIONS被客戶端錯誤設置爲小寫,導致服務端異常。但是通過抓包看到OPTIONS請求正確返回(status: 204),並且後端日誌中並未收到小寫的OPTIONS請求。所以這個排除。
然後着眼於服務端返回的相關HTTP頭
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: *
Access-Control-Allow-Methods: *
本地復現出來,並排查是因爲Access-Control-Allow-Headers: * 導致的,這個屬性有某些兼容性問題。
Access_Control_Allow_Headers: *
MDN中介紹 Access-Control-Allow-Headers: * 有兩重意思。
一個是在服務端設置Access-Control-Allow-Credentials: true的時候這個 * 只會被客戶端當做字符串 * (我們不希望的,會出錯的)。
另一個是沒有這個設置則會被當做通配符(我們希望的,不會出錯的)。
當然這裏響應頭中並沒有Access-Control-Allow-Credentials: true設置,但還是出錯了。
猜測是客戶端對於 * 的實現上有兼容性問題,所以建議不要這樣設置,用到什麼設置什麼最好,例如:Access-Control-Allow-Headers: Content_Type。
之後成功排除了問題。
結論
Access-Control-Allow-Headers: * 在部分客戶端上有兼容問題。
注:跨域錯誤是不會暴露給JS的,就意味着 corsError.message 拿不到錯誤的具體信息,不太好在沒有控制檯的環境看到問題。