现有系统已经有一套完整的接口,用户状态,验证都是基于饼干的。
部分业务要上小程序版本,众所周知,微信小程序不支持饼干的。要上线的业务,最好的方式还是基于现有这套接口做,改动不大,也最快。
通过浏览器的开发工具,网络栏查看请求,浏览器中的cookie会携带在每个http的请求头里面,用饼干作为键名。
那么,在微信官方请求方式wx。请求中,我们设置头,添加一个饼干应该可以得以模拟。
问题又来了,怎么获取到服务器返回的饼干呢。
通过登录接口(登录的时候,服务器端会植入饼作为会话),查看http返回头。
wx.request ({ url:/api/登录, 成功:(数据)=比;{ 如果(数据)。statusCode===200) { console.log(数据);//数据中应该会有set - cookie或set - cookie的字样,嗯,那就是服务器种下的饼干 } } }) >之前拿到饼干存入本地中,下次请求数据的时候直接塞进去,完美。
原本以为饼干只需要一进一出就可以完美模拟,实际操作才发现,携带上去的饼干服务器无法识别。
服务器返回的饼干中,会携带上很多储存用的字段,例如路径=/;
//服务器放回的饼干 让饼干=' userKey=1234567890;同名路径=/;到期=星期四,2018年6月21日13:15:08格林尼治时间;HttpOnly,用户id=111;路径=/;日格林尼治时间到期=星期四,2018年6月21日13:15:08昵称=;路径=/;日格林尼治时间到期=星期四,2018年6月21日13:15:08用户名=111111;路径=/;日格林尼治时间到期=星期四,2018年6月21日13:15:08 imgUrl=;路径=/;到期=星期四,2018年6月21日格林尼治时间13:15:08 ';//模拟的是需要的格式样式 让virtualCookie=' userKey=1234567890;同名用户名=111111;用户id=111;”; >之前妈耶~要怎么过滤呢。
简单粗糙的写了一个过滤方案。
//cookie的本地存储位置 const COOKIE_KEY=癬_cookie_key__”;/* * *格式化用户需要的饼干 */const normalizeUserCookie=(饼干=")=比;{ 让__cookies=[]; (cookies.match (/((\ w \] *)=([^ \ s=] +);/g) | | []) .forEach ((str)=比;{ 如果(str !===/;路径的,,str.indexOf (csrfToken=) !==0) { __cookies.push (str); } }); wx。setStorageSync (COOKIE_KEY __cookies。加入(' ')); }; >之前<代码> csrfToken> 代码是接下来配合<代码>鸡蛋。js> 代码用的,<代码>=/;路径> 代码在某些应用下会是<代码>=/;路径代码>
<代码> normalizeUserCookie 代码>主要是过滤了<代码> xx=xxx> 代码;这样的数据,然后排除<代码>=/;路径代码>这样无意义的数据。
在登录接口的时候,存上饼干,在接下来的请求中带上,那么,应该,没错,可能,可以模拟了。
鸡蛋内置的<代码> egg-security> 代码插件默认对所有“非安全”的方法,例如邮报》说,删除都进行CSRF校验。
鸡蛋。js虽然可以在配置中关闭CSRF,但是,如果一定要使用呢?首先,要弄明白一件事,<代码> csrfToken 代码>怎么来的。
经过多次验证得知,当http请求时,在约定位置没有携带上csrfToken值,此次请求会在返回的cookie中携带上一个新的csrfToken;当本次请求已携带上值,就不会产生成csrfToken。当约定位置带上的csrfToken与饼干里面的csrfToken一致时,通过验证。
接上面的<代码>格式化用户需要的饼干代码>操作,先抛开csrfToken单独处理用户状态等。
在每次请求结束后,试着单独拿饼干中可能存在的csrfToken,有值就缓存,没值跳过用旧值。
本次小程序是基于wepy的,所以使用了优化后的<代码> wepy.request> 代码;
基于鸡蛋。js的版本。
可能与实际开发有点出入,适当修改。
从“进口wepy wepy '; 出口const HTTP_HOST=' http://127.0.0.1:3000 '; 出口const HTTP_HOST_API=' $ {HTTP_HOST}/api/wxmp”;//cookie的本地存储位置 const COOKIE_KEY=癬_cookie_key__”;//csrfToken的本地存储位置 const CSRF_TOKEN_KEY=癬_csrf_token__”;/* * *清除用户饼干 */出口const cleanUserCookie=()=比;{ wx。setStorageSync (COOKIE_KEY”); }/* * *格式化用户需要的饼干 * @param{字符串}饼干 */出口const normalizeUserCookie=(饼干=")=比;{ 让__cookies=[]; (cookies.match (/((\ w \] *)=([^ \ s=] +);/g) | | []) .forEach ((str)=比;{ 如果(str !===/;路径的,,str.indexOf (csrfToken=) !==0) { __cookies.push (str); } }); wx。setStorageSync (COOKIE_KEY __cookies); };/* * *格式化令牌 */const normalizeCsrfToken=()=比;{ 让__value=https://www.yisu.com/zixun/wx.getStorageSync (CSRF_TOKEN_KEY) | |”; 让__inputs=__value.match (/csrfToken=[\ S] */) | | []; 让__key=__inputs [0];//csrfToken=1212132323; 如果(! ! ! __key) { 返回”; }//脱水 返回__key.replace(/,/美元”)。替换(/^ csrfToken=/?; };/* * *保存csrf的饼干 *不一定每次请求都会更新饼干 * @param{字符串}饼干 */const seveCsrfTokenCookie=(饼干)=比;{ 如果(饼干){ wx。setStorageSync (CSRF_TOKEN_KEY、饼干); } };/* * *请求数据 * @param}{对象选择 */出口const doAjax=(选择)=比;{ 返回新的承诺((解决,拒绝)=比;{ 让饼干=wx.getStorageSync (COOKIE_KEY) | | []; 让csrf=normalizeCsrfToken (); 让url=opt.url;//整理饼干 Cookies.push (“csrfToken=$ {csrf};”);//设置请求头部 opt.header=Object.assign ( { “x-csrf-token”:攻击, 饼干:饼干。加入(' ') }, opt.header | | {} ); opt.success=(数据)=比;{ seveCsrfTokenCookie (data.header [' set - cookie ']);//统一操作 如果(数据)。statusCode==200) { 如果(url===/登录){ normalizeUserCookie (data.header [' set - cookie ']); } 解决(data.data); 其他}{ 拒绝(“未知错误,请重试一次”); } }; opt.fail=(err)=比;{ 拒绝(错); }; opt.url=" $ {HTTP_HOST_API} $ {opt.url} '; wepy.request(选择); }); };微信小程序模拟饼干的实现