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

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

Flying
2017-06-28 / 0 评论 / 145 阅读 / 正在检测是否收录...

最近 Node.js 用得比较多,遇到的问题也比较多。在使用 Koa 获取 cookie 时。我发现不支持中文。回想我们用 Express 的 cookie-parser 中间件没有这个问题呀。他们的实现有什么不一样吗?分析原码后我大概明白了其中原因。

globe-node.svg

问题分析

代码片段如下。


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.jscookies.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!

8

评论 (0)

取消