在使用公司平臺提供的組件時,遇到在6s、7p時出現白屏情況,通過review代碼發現平臺的組件使用了URLSearchParams和es6 的includes。
通過caniuse.com 或者MDN查看 URLSearchParams兼容發現,對於低版本的IOS 10.3 ( 2017 年 3月發佈)以下是不支持的。
使用URLSearchParams 實現URL拼接源碼:
export function contactUrl (url = '', params = {}) {
let qs = new URLSearchParams()
for (let key in params) {
qs.append(key, params[key])
}
if (url.includes('?')) {
return url + '&' + qs.toString()
} else {
return url + '?' + qs.toString()
}
}
如何解決?
1、使用url-search-params-polyfill
2、自己使用字符串拼接URL
乍一看這實現很簡單很好修改,直接使用字符串拼接方式:
對於簡單的參數(字符串,數字)這樣處理是沒有問題的,如果傳入的params 中存在特殊參數(加密串),這種簡單處理就出現無法匹配的問題了。
項目中正好有個特殊參數加密session_id ,使用上面的實現出現無法通過校驗的問題。對比2個方式的請求URL發現session_id長度不一致,嘗試過多種方式都無效,最後參考url-search-params-polyfill 是如何實現的。
URLSearchParamsPolyfill源碼分析
在url-search-params-polyfill的 index.js 中,我們看到append(name, value)的實現是調用appendTo() 將name, value 作爲一個數組的key , value 存儲在this身上。
直接看appendTo(dirct, name ,value) 方法(append 調用中dirct 指向 對象this):
function appendTo(dict, name, value) {
var val = typeof value === 'string' ? value : (
value !== null && value !== undefined && typeof value.toString === 'function' ? value.toString() : JSON.stringify(value)
);
if (name in dict) {
dict[name].push(val);
} else {
dict[name] = [val];
}
}
append 沒有特殊,再來看下URLSearchParamsPolyfill中的toString方法:
prototype.toString = function() {
var dict = this[__URLSearchParams__], query = [], i, key, name, value;
for (key in dict) {
name = encode(key);
for (i = 0, value = dict[key]; i < value.length; i++) {
query.push(name + '=' + encode(value[i]));
}
}
return query.join('&');
};
遍歷this對象每個元素,並對每個元素進行encode後拼接成參數字符('a=b&c=d')。
重點就在於對每個元素encode 方法,通過源碼分析它的實現並不是簡單進行encodeURIComponent , 同時進行了字符串進行編碼escape。
function encode(str) {
var replace = {
'!': '%21',
"'": '%27',
'(': '%28',
')': '%29',
'~': '%7E',
'%20': '+',
'%00': '\x00'
};
return encodeURIComponent(str).replace(/[!'\(\)~]|%20|%00/g, function(match) {
return replace[match];
});
}
看到這裏就已經很明瞭,URLSearchParams在對象調用toString時對元素參數進行的處理。
最後在自我實現的方法拼接字符串的時候添加相應的字符編碼處理,把問題解決了。
參考資料: