在百度小程式中對set-cookie的處理

JS老狗發表於2018-12-05

在後端API返回的響應頭中,包含了12條set-cookie

百度小程式(以及微信小程式)對此的處理是:將多個同名的響應頭用半形逗號,JOIN成一長串字串。原因是因為response.header是一個Object物件。

由於cookie資訊中往往會存在Expires過期時間資訊,而這種GMT時間格式是有可能存在半形逗號的,會與header的JOIN字元衝突,所以如果簡單使用

cookieStr.split(',')
複製程式碼

來切割cookie,會導致cookie解析不正確。看一下cookie樣本:

let badCookie = `
    route=xxx; Path=/,
    authId=xxx;domain=.xxx.com;path=/;HTTPOnly;, 
    secureToken=xxx;domain=.xxx.com;path=/;secure;HTTPOnly;, 
    path=/; domain=.xxx.com; Max-Age=1728000; 
    Expires=Sat, 22-Dec-2018 05:30:39 GMT, 
    
`;
複製程式碼

採用的處理方式也比較簡單粗暴:進行特殊值保護

在切割cookie之前,先對引起衝突的日期做轉換,保護日期值不會被split破壞。

export const pluginFixGMTDateTime = cookie =>
    (cookie + '').replace(
        /\=(Mon|Tue|Wed|Thu|Fri|Sat|Sun)\s*\,/g,
        '=$1'
    );
複製程式碼

除此之外,我們還需要對cookie做頭尾去空字串、整體去換行符等清理工作。

export const pluginTrim = s =>
    (s + '').replace(/^\s+|\s+$/g, '');

export const pluginLinear = s =>
    (s + '').replace(/[\r\n]+/g, '');
複製程式碼

用外掛形式寫清理方法,目的是方便以後擴充套件。

在進行切割之前,我們先把外掛組織起來,做一個專門的清理工具:

export const prepareString = (s, ...plugin) => {
    plugin = [
        pluginTrim,
        pluginLinear,
        pluginFixGMTDateTime,
        ...plugin
    ];
    return plugin.length < 1
        ? s
        : plugin.length === 1
            ? plugin[0](s)
            : plugin.reduce((a, b) => 
                typeof(a) === 'function' ? b(a(s)) : b(a)
            );
};
複製程式碼

在cookie切割之後,我們還需要將每一個key-value結構的鍵值對取出來,依然用正則:

export const cookieItemRegExp = 
    /([\w\-_]+)(\s*\=\s*((Mon|Tue|Wed|Thu|Fri|Sat|Sun).+?GMT|[^;\,]+))?/g
    ;
複製程式碼

這裡的正則其實也包含特殊值保護,但cookie是一種特殊結構,需要按條解析,所以不能直接用此正則匹配cookie全文。

現在都已經準備好了,我們可以開始動手解析cookie了:

export const cookieParser = (cookie, ...plugin) => {
    let cleanCookie = prepareString(cookie + '', ...plugin);
    let cookieSegments = cleanCookie.split(',').map(s => pluginTrim(s));
    let cookies = [];
    cookieSegments.forEach(cookieStr => {
        if(cookieStr.length < 1) return;
        let ms = cookieStr.match(cookieItemRegExp), cookieObj = {};
        if(ms){
            ms.forEach(m => {
                let idx = m.indexOf('='), key, val;
                if(idx > -1){
                    key = m.substr(0, idx);
                    val = m.substr(idx + 1);
                } else {
                    key = m;
                    val = null;
                }
                cookieObj[key] = val;
            })
        }
        cookies.push({ cookieStr, cookieObj })
    });
    return cookies;
};
複製程式碼

解析badCookie輸出結果

在百度小程式中對set-cookie的處理

相關文章