单页应用处理 406 状态

书接上文,上篇文章已经解决了单点登录里 session 处理的问题,这篇我们聊聊用户登出后,用户操作页面,服务返回 406 报错问题。

406 Not Acceptable

客户端出现这个状态码意味着,当前接口的返回数据没有匹配 request headeracceptable values 的要求,具体的配置的点如下:

  • Accept:客户端支持的内容类型,用 MIME 类型表示,
    • Accept: <MIME_type>/<MIME_subtype>
    • Accept: <MIME_type>/*
    • Accept: */*
    • 实例 Accept: text/html, application/xhtml+xml, application/xml;q=0.9, */*;q=0.8(此处的 q 表示权重,所有值根据对应权重大小排序)
  • Accept-Charset:客户端支持的字符编码,例 Accept-Charset: utf-8, iso-8859-1;q=0.5, *;q=0.1
  • Accept-Encoding:客户端支持的内容编码方式,
    • 压缩算法如 gzip、compress、deflate、br
    • identity,标记支持无压缩
    • *
    • Accept-Encoding: deflate, gzip;q=1.0, *;q=0.5
  • Accept-Language:客户端支持的语言
    • Accept-Language: <language>
    • Accept-Language: *
    • 实例 Accept-Language: en-US,en;q=0.5

场景

用户当前同时开着 A、B 系统的窗口,在 B 系统中退出,在 A 系统中页面操作,请求的接口返回 406 Not Acceptable,出现原因是服务端鉴权发现当前请求无用户状态后,直接通过 ctx.redirect('/login') 企图跳转到登录页面,但 redirect 时,请求返回内容格式就成了 HTML 格式,但客户端的 ajax 配置了 Accept: application/json;,客户端收到了 HTML,心想这不是糊弄我吗,果断 throw 了一个 406。

方案

在后端权限校验逻辑决定 redirect 前,使用 ctx.assert(ctx.request.accepts('html'),406,'User not found. Please login!',); 判断当前请求是否支持 HTML 内容,如不支持直接服务端返回 406 错误,前端请求方法初判断返回是否是 406,返回 406 时,直接 reload 页面。