最近 Node.js 用得比较多,遇到的问题也比较多。在使用 Koa 获取 cookie 时。我发现不支持中文。回想我们用 Express 的 cookie-parser
中间件没有这个问题呀。他们的实现有什么不一样吗?分析原码后我大概明白了其中原因。
问题分析
代码片段如下。
router.get('/', async (ctx) => {
const userinfo = '张三'
ctx.cookies.set('userinfo', userinfo, {
maxAge: 60 * 1000 * 60
});
})
router.get('/news', async (ctx) => {
const userinfo = ctx.cookies.get('userinfo');
console.log(userinfo)
})
一跑 Node,结果出错。
报错:TypeError: argument value is invalid at new Cookie...
原来 Koa 的 cookie 默认不支持中文。但为什么不支持中文呢?一跟代码,原来 Koa 依赖 cookies.js
。cookies.js
下述正则表达式对 cookie 值进行类型检查时将中文排除在外,所以抛出参数值类型不正确的错误。
/^[\u0009\u0020-\u007e\u0080-\u00ff]+$/
咱们中文的 Unicode 码在 [\u4E00-\u9FA5] 范围之间,只要告知 cookies.js
的作者将那个正则表达式加上中文字符的区间就可以了吗?想法是美好的,但还是 Too young too simple。我试了即使改了那个正则表达式,还是会报错。
报错:TypeError [ERR_INVALID_CHAR]: Invalid character in header content ["Set-Cookie"]。
原来 cookies 在请求和响应时都是通过 Header 的。按照 Web 标准的说法,Http Header 有一定的格式要求,所以老外这么写是对的。
解决办法
怎么解决这个问题呢?还得参考 cookie-parser.js
的方案。看这个中间件的源代码,它在设置 cookies 时调用了 cookies.parse
方法,该方法的源码片段如下 :
function parse(str, options) {
if (typeof str !== 'string') {
throw new TypeError('argument str must be a string');
}
var obj = {}
var opt = options || {};
var pairs = str.split(pairSplitRegExp);
var dec = opt.decode || decode;
......
return obj;
}
由此可见,该方法会按键值对的方式将 cookies
解析成对象,并使用 decodeURIComponent
对值解码。所以,我们对中文 cookies 值硬编码就能支持中文了。
最简单的办法是使用 encodeURIComponent/decodeURIComponent
。如下修改:
router.get('/', async (ctx) => {
const userinfo = '张三'
ctx.cookies.set('userinfo', encodeURIComponent(userinfo), {
maxAge: 60 * 1000 * 60
});
})
router.get('/news', async (ctx) => {
const userinfo = decodeURIComponent(ctx.cookies.get('userinfo'));
console.log(userinfo)
})
当然,使用 Buffer
操作也是可行的。
😀 Happy coding!
评论 (0)