发现问题
由于这是前人写的代码,出现问题时没有太多实现逻辑和记忆可参考。
测试环境在某些时候接口会报错 413 Request Entity Too Large
, 初步观察是由于 Cookie 带有重复的授权信息导致。
导致问题的原因
同一个 host 的不同端口下有不同的应用创建不同的 Cookie, 当某个 API 发起请求时,会带上所有应用的 Cookie,导致 Cookie 长度过大。
进入一同个 IP 下的某端口登录应用,这时候会向浏览器写入 Cookie。
随着不同端口的应用越来越多,存储的 Cookie 越来越多。
当某个 API 发起请求时,会带上所有应用的 Cookie,导致 Cookie 长度过大。
达到一定程序时,就会触发 http 服务的 header 长度限制,导致请求失败。
浏览器演示
postman 演示
为什么开发环境没有发现此问题
- 不同的人开发不同的项目,不会造成多个项目的 Cookie 累加的情况
- 有 localhost/127.0.0.1/192.x.x.x 可以访问同一个项目
- 当正常退出时 Cookie 会被清除
疑问
Cookie 是前端写的后端写的
为什么会有这个疑问?因为都知道前后端都可以写 Cookie,并且后端可以决定是否携带 Cookie。那么如果假设这个 Cookie 就是后端写的,那这个问题就应该由后端去解决。
从接口 Response 信息以及前端代码 Cookies.set 相关代码基本可以确定 Cookie 是前端写入的。
是否后端要求的就是当前所需的实现呢(携带其他端口下的 Cookie)
如果是,那么这个问题也应该由后端去解决。
根据经验,我们先假设不是。
假设依据:
- 存在有 Authorization/Blade-Auth 类似授权字段
- 不包含其他端口 Cookie 时系统也可正常使用
- 携带其他端口的 Cookie 是 rfc 规范规定的,
Cookie 不提供端口隔离
同时存在多个类似授权的 header
查看 API 的请求报文,可以发现以下 3 个类似授权的 header:
- Authorization: xxx
- Blade-Auth: xxx
- Cookie: xxx
那么问题来了,这三个字段有什么不同?到底哪个是用于授权的?
由于存在 Authorization/Blade-Auth 字段,先假设 Cookie 是没有用的,或者 Cookie 只是用于暂存授权信息。
观察请求报文,Blade-Auth 中的值其实就是 Cookie 中的某一条目的值,所以如果 Blade-Auth 是授权字段,则此 Cookie 可以省略。
通过代码基本确定 Cookie 只是用于暂存授权信息。
PS: 当我去问后端到底是用哪个字段做的授权时,后端说他去看代码很麻烦,让我前端自己去测试。我说我可以测试出来带哪个参数行,哪个参数不行,但授权服务不是我写的,我没有保证权。他还是拒绝告诉我这个字段。好吧。
假设通过去除 Cookie 的方案,是否造成新的问题
假设去除 Cookie ,后端接口可以使用成功吗?
产生找到一个带授权的 GET 请求,居然不带任何授权字段都能通过,难道后端故意对 GET 放宽了权限?
于是我拿到了个创建助手的 POST 请求,同样不带任何授权字段都可以创建成功!
震惊,后端根本没授权,那要登录做什么?是不是每个应用都这样的?
然后我又换到另一个应用测试:
经测试,另一个应用需要带授权字段,且这个字段是 blade-auth,其他的 Authorization/Cookie 都可以不要,这次我就简单上个图。
另外,假设删除 Cookie,那么会影响下次 token 自动获取吗?会影响 token 自动更新逻辑吗?这又得进行一波代码逻辑分析……
根据 RefreshTokenKey 这个关键字,表明框架应该使用了 jwt 授权逻辑的 过期标志获取新 token
的方案,但搜索发现此方案并未落实,然后实现有可能变成在 API 调用后 token 自动续期,或者到期后用户需要重新登录。
但是删除 Cookie 后肯定是影响刷新页面后的已有 token 获取的,所以这时候要把存 Cookie 这个逻辑变为存 lcoalStore,这样存就不会带上无关 Cookie 了。
假设去除 Cookie ,会影响未来的功能吗?
那肯定是会的,如果将来某个接口需要 Cookie, 还得专门针对这个接口做逻辑编写不说,这个接口还是会出现带上其他端口信息的问题。
假设通过域名隔离的方案,是否造成新的问题
对于此方案,可以不修改前端任何代码,且可以使用 cookie 参数指定隔离情况。仅把部署方式部署到不同的域名(例如使用子域名区分应用,而不是使用端口区分应用)即可解决问题。
前端不用修改的原因是:当前的 Cookie 本身就当授权信息存储使用,当更改部署方式之后,只是存储的键不一样,根据前端当前的逻辑照样可以正常读写。
理论上后端代码也不需要修改。
不过,修改之后需要发布新的可用链接,即需要告知使用的人员新的地址,造成一点沟通成本,如果要避免这个沟通成本也是可以的,对原来的地址做一个重定向即可。
总结
方案一:把 token 存在 store 中,自定义管理 token 销毁逻辑。
去除 Cookie 携带(建议后端明确给出授权字段)。
方案二:使用子域名方式部署应用。
经讨论预选:方案二。