本篇文章主要介紹了微信小程序模擬 cookie的實(shí)現(xiàn),內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。
開(kāi)發(fā)背景
現(xiàn)有系統(tǒng)已經(jīng)有一套完整的接口,用戶(hù)狀態(tài)、驗(yàn)證都是基于 cookie 的。
部分業(yè)務(wù)要上小程序版本,眾所周知,微信小程序不支持 cookie 的。要上線的業(yè)務(wù),最好的方式還是基于現(xiàn)有這套接口做,改動(dòng)不大,也最快。
模擬 cookie
通過(guò)瀏覽器的開(kāi)發(fā)工具,Network 欄查看請(qǐng)求,瀏覽器中的 cookie 會(huì)攜帶在每個(gè) http 的 Request Headers 里面,用 Cookie 作為鍵名。
那么,在微信官方請(qǐng)求方式 wx.request 中,我們?cè)O(shè)置 header,添加一個(gè) Cookie 應(yīng)該可以得以模擬。
問(wèn)題又來(lái)了,怎么獲取到服務(wù)器返回的 cookie 呢。
通過(guò)登錄接口(登錄的時(shí)候,服務(wù)器端會(huì)植入 cookie 作為 session),查看 http 返回頭。
wx.request({ url: '/api/login', success: (data) => { if(data.statusCode === 200) { console.log(data); // data 中應(yīng)該會(huì)有 Set-Cookie 或 set-cookie 的字樣,嗯,那就是服務(wù)器種下的 cookie } } })
拿到 cookie 存入本地中,下次請(qǐng)求數(shù)據(jù)的時(shí)候直接塞進(jìn)去,完美。
格式化 cookie
原本以為 cookie 只需要一進(jìn)一出就可以完美模擬,實(shí)際操作才發(fā)現(xiàn),攜帶上去的 cookie 服務(wù)器無(wú)法識(shí)別。
服務(wù)器返回的 cookie 中,會(huì)攜帶上很多儲(chǔ)存用的字段,例如 path=/;
// 服務(wù)器放回的 cookie let cookie = 'userKey=1234567890; Path=/; Expires=Thu, 21 Jun 2018 13:15:08 GMT; HttpOnly,userId=111; Path=/; Expires=Thu, 21 Jun 2018 13:15:08 GMT,nickName=; Path=/; Expires=Thu, 21 Jun 2018 13:15:08 GMT,userName=111111; Path=/; Expires=Thu, 21 Jun 2018 13:15:08 GMT,imgUrl=; Path=/; Expires=Thu, 21 Jun 2018 13:15:08 GMT'; // 模擬的是需要的格式樣式 let virtualCookie = 'userKey=1234567890; userName=111111; userId=111;';
媽耶~要怎么過(guò)濾呢。
簡(jiǎn)單粗糙的寫(xiě)了一個(gè)過(guò)濾方案。
// cookie 的本地存儲(chǔ)位置 const COOKIE_KEY = '__cookie_key__'; /** * 格式化用戶(hù)需要的 cookie */ const normalizeUserCookie = (cookies = '') => { let __cookies = []; (cookies.match(/([\w\-.]*)=([^\s=]+);/g) || []).forEach((str) => { if (str !== 'Path=/;' && str.indexOf('csrfToken=') !== 0) { __cookies.push(str); } }); wx.setStorageSync(COOKIE_KEY, __cookies.join(' ')); };
csrfToken 是接下來(lái)配合 Egg.js 用的,Path=/; 在某些應(yīng)用下會(huì)是 path=/;
normalizeUserCookie 主要是過(guò)濾了 xx=xxx; 這樣的數(shù)據(jù),然后排除 path=/; 這樣無(wú)意義的數(shù)據(jù)。
在登錄接口的時(shí)候,存上 cookie,在接下來(lái)的請(qǐng)求中帶上,那么,應(yīng)該、沒(méi)錯(cuò)、可能、可以模擬了。
配合 Egg.js
Egg 內(nèi)置的 egg-security 插件默認(rèn)對(duì)所有『非安全』的方法,例如 POST,PUT,DELETE 都進(jìn)行 CSRF 校驗(yàn)。
Egg.js 雖然可以在配置中關(guān)閉 CSRF,但是,如果一定要使用呢?
首先,要弄明白一件事,csrfToken 怎么來(lái)的。
經(jīng)過(guò)多次驗(yàn)證得知,當(dāng) http 請(qǐng)求時(shí),在約定位置沒(méi)有攜帶上 csrfToken 值,此次請(qǐng)求會(huì)在返回的 cookie 中攜帶上一個(gè)新的 csrfToken;當(dāng)本次請(qǐng)求已攜帶上值,就不會(huì)產(chǎn)生成 csrfToken。當(dāng)約定位置帶上的 csrfToken 與 cookie 里面的 csrfToken 一致時(shí),通過(guò)驗(yàn)證。
接上面的 格式化用戶(hù)需要的 cookie 操作,先拋開(kāi) csrfToken 單獨(dú)處理用戶(hù)狀態(tài)等。
在每次請(qǐng)求結(jié)束后,試著單獨(dú)拿 cookie 中可能存在的 csrfToken,有值就緩存,沒(méi)值跳過(guò)用舊值。
封裝一個(gè) Ajax
本次小程序是基于 wepy 的,所以使用了優(yōu)化后的 wepy.request;
基于 Egg.js 的版本。
可能與實(shí)際開(kāi)發(fā)有點(diǎn)出入,適當(dāng)修改。
import wepy from 'wepy'; export const HTTP_HOST = 'http://127.0.0.1:3000'; export const HTTP_HOST_API = `${HTTP_HOST}/api/wxmp`; // cookie 的本地存儲(chǔ)位置 const COOKIE_KEY = '__cookie_key__'; // csrfToken 的本地存儲(chǔ)位置 const CSRF_TOKEN_KEY = '__csrf_token__'; /** * 清除用戶(hù)Cookie */ export const cleanUserCookie = () => { wx.setStorageSync(COOKIE_KEY, ''); } /** * 格式化用戶(hù)需要的 cookie * @param {String} cookies */ export const normalizeUserCookie = (cookies = '') => { let __cookies = []; (cookies.match(/([\w\-.]*)=([^\s=]+);/g) || []).forEach((str) => { if (str !== 'path=/;' && str.indexOf('csrfToken=') !== 0) { __cookies.push(str); } }); wx.setStorageSync(COOKIE_KEY, __cookies); }; /** * 格式化 token */ const normalizeCsrfToken = () => { let __value = wx.getStorageSync(CSRF_TOKEN_KEY) || ''; let __inputs = __value.match(/csrfToken=[\S]*/) || []; let __key = __inputs[0]; // csrfToken=1212132323; if (!!!__key) { return ''; } // 脫水 return __key.replace(/;$/, '').replace(/^csrfToken=/, ''); }; /** * 保存 csrf 的cookie * 不一定每次請(qǐng)求都會(huì)更新 cookie * @param {String} cookie */ const seveCsrfTokenCookie = (cookie) => { if (cookie) { wx.setStorageSync(CSRF_TOKEN_KEY, cookie); } }; /** * 請(qǐng)求數(shù)據(jù) * @param {Object} opt */ export const doAjax = (opt) => { return new Promise((resolve, reject) => { let Cookies = wx.getStorageSync(COOKIE_KEY) || []; let csrf = normalizeCsrfToken(); let url = opt.url; // 整理 Cookie Cookies.push(`csrfToken=${csrf};`); // 設(shè)置請(qǐng)求頭部 opt.header = Object.assign( { 'x-csrf-token': csrf, Cookie: Cookies.join(' ') }, opt.header || {} ); opt.success = (data) => { seveCsrfTokenCookie(data.header['set-cookie']); // 統(tǒng)一操作 if (data.statusCode == 200) { if (url === '/login') { normalizeUserCookie(data.header['set-cookie']); } resolve(data.data); } else { reject('未知錯(cuò)誤,請(qǐng)重試一次'); } }; opt.fail = (err) => { reject(err); }; opt.url = `${HTTP_HOST_API}${opt.url}`; wepy.request(opt); }); };
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,更多相關(guān)內(nèi)容請(qǐng)關(guān)注PHP中文網(wǎng)!
相關(guān)推薦:
以上就是微信小程序模擬cookie的實(shí)現(xiàn)的詳細(xì)內(nèi)容,更多請(qǐng)關(guān)注有卡有網(wǎng)。