微信小程序模拟cookie的实现
开发背景
现有系统已经有一套完整的接口,用户状态、验证都是基于cookie的。
部分业务要上小程序版本,众所周知,微信小程序不支持cookie的。要上线的业务,最好的方式还是基于现有这套接口做,改动不大,也最快。
模拟cookie
通过浏览器的开发工具,Network栏查看请求,浏览器中的cookie会携带在每个http的RequestHeaders里面,用Cookie作为键名。
那么,在微信官方请求方式wx.request中,我们设置header,添加一个Cookie应该可以得以模拟。
问题又来了,怎么获取到服务器返回的cookie呢。
通过登录接口(登录的时候,服务器端会植入cookie作为session),查看http返回头。
wx.request({
url:'/api/login',
success:(data)=>{
if(data.statusCode===200){
console.log(data);
//data中应该会有Set-Cookie或set-cookie的字样,嗯,那就是服务器种下的cookie
}
}
})
拿到cookie存入本地中,下次请求数据的时候直接塞进去,完美。
格式化cookie
原本以为cookie只需要一进一出就可以完美模拟,实际操作才发现,携带上去的cookie服务器无法识别。
服务器返回的cookie中,会携带上很多储存用的字段,例如path=/;
//服务器放回的cookie letcookie='userKey=1234567890;Path=/;Expires=Thu,21Jun201813:15:08GMT;HttpOnly,userId=111;Path=/;Expires=Thu,21Jun201813:15:08GMT,nickName=;Path=/;Expires=Thu,21Jun201813:15:08GMT,userName=111111;Path=/;Expires=Thu,21Jun201813:15:08GMT,imgUrl=;Path=/;Expires=Thu,21Jun201813:15:08GMT'; //模拟的是需要的格式样式 letvirtualCookie='userKey=1234567890;userName=111111;userId=111;';
妈耶~要怎么过滤呢。
简单粗糙的写了一个过滤方案。
//cookie的本地存储位置
constCOOKIE_KEY='__cookie_key__';
/**
*格式化用户需要的cookie
*/
constnormalizeUserCookie=(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是接下来配合Egg.js用的,Path=/;在某些应用下会是path=/;
normalizeUserCookie主要是过滤了xx=xxx;这样的数据,然后排除path=/;这样无意义的数据。
在登录接口的时候,存上cookie,在接下来的请求中带上,那么,应该、没错、可能、可以模拟了。
配合Egg.js
Egg内置的egg-security插件默认对所有『非安全』的方法,例如POST,PUT,DELETE都进行CSRF校验。
Egg.js虽然可以在配置中关闭CSRF,但是,如果一定要使用呢?
首先,要弄明白一件事,csrfToken怎么来的。
经过多次验证得知,当http请求时,在约定位置没有携带上csrfToken值,此次请求会在返回的cookie中携带上一个新的csrfToken;当本次请求已携带上值,就不会产生成csrfToken。当约定位置带上的csrfToken与cookie里面的csrfToken一致时,通过验证。
接上面的格式化用户需要的cookie操作,先抛开csrfToken单独处理用户状态等。
在每次请求结束后,试着单独拿cookie中可能存在的csrfToken,有值就缓存,没值跳过用旧值。
封装一个Ajax
本次小程序是基于wepy的,所以使用了优化后的wepy.request;
基于Egg.js的版本。
可能与实际开发有点出入,适当修改。
importwepyfrom'wepy';
exportconstHTTP_HOST='http://127.0.0.1:3000';
exportconstHTTP_HOST_API=`${HTTP_HOST}/api/wxmp`;
//cookie的本地存储位置
constCOOKIE_KEY='__cookie_key__';
//csrfToken的本地存储位置
constCSRF_TOKEN_KEY='__csrf_token__';
/**
*清除用户Cookie
*/
exportconstcleanUserCookie=()=>{
wx.setStorageSync(COOKIE_KEY,'');
}
/**
*格式化用户需要的cookie
*@param{String}cookies
*/
exportconstnormalizeUserCookie=(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
*/
constnormalizeCsrfToken=()=>{
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
*不一定每次请求都会更新cookie
*@param{String}cookie
*/
constseveCsrfTokenCookie=(cookie)=>{
if(cookie){
wx.setStorageSync(CSRF_TOKEN_KEY,cookie);
}
};
/**
*请求数据
*@param{Object}opt
*/
exportconstdoAjax=(opt)=>{
returnnewPromise((resolve,reject)=>{
letCookies=wx.getStorageSync(COOKIE_KEY)||[];
letcsrf=normalizeCsrfToken();
leturl=opt.url;
//整理Cookie
Cookies.push(`csrfToken=${csrf};`);
//设置请求头部
opt.header=Object.assign(
{
'x-csrf-token':csrf,
Cookie:Cookies.join('')
},
opt.header||{}
);
opt.success=(data)=>{
seveCsrfTokenCookie(data.header['set-cookie']);
//统一操作
if(data.statusCode==200){
if(url==='/login'){
normalizeUserCookie(data.header['set-cookie']);
}
resolve(data.data);
}else{
reject('未知错误,请重试一次');
}
};
opt.fail=(err)=>{
reject(err);
};
opt.url=`${HTTP_HOST_API}${opt.url}`;
wepy.request(opt);
});
};
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。