分类
Javascript

解决Koa cookie不支持中文的问题

最近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有个正则表达式/^[\u0009\u0020-\u007e\u0080-\u00ff]+$/对cookie值进行类型检查时将中文排除在外,所以抛出参数值类型不正确的错误。

咱们中文的Unicode码在[\u4E00-\u9FA5]范围之间,只要告知cookies.js的作者将那个正则表达式加上中文字符的区间就可以了吗?想法是美好的,但还是Too young too simple。我试了即使改了那个正则表达式,还是会报错。ypeError [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!