【BUG排查记】HttpUtil和SpringSecurity结合的坑

一、背景

   最近为了做微服务高可用和优化上线流程,我参与了一个微服务的改造开发。
   主要包括redis切换哨兵模式、接入高可用xxljob集群、配置和升级脚本优化。

二、问题描述

项目改造提测后,测试发现一个依赖远程http调用的功能不可用

三、问题分析

查看被调用方日志发现通用Token解析错误如下图

说明调用时传入了错误的Token,查看调用方代码:

复制代码
# 使用hutool工具发起远程http请求
HashMap<String, String> headers = getHeader(modelSyncGitDto);
HttpRequest request = HttpUtil.createRequest(Method.POST, url);
HttpResponse execute = request
        .addHeaders(headers)
        .timeout(2000)
        .body(JSONUtil.toJsonStr(modelSyncGitDto))
        .execute();
# 通用工具生成jwt token放入header
private HashMap<String, String> getHeader(ModelSyncGitDto modelSyncGitDto){
    String userJwtToken = JwtUtils.getJwtToken(filterConfig.getAcSecret(),null,modelSyncGitDto.getComputerUserName(),modelSyncGitDto.getOsName());
    HashMap<String, String> headers = new HashMap<>(200);
    headers.put("Token", userJwtToken);
    return headers;
}

以上调用代码无问题,继续排查被调用方解析token的代码

复制代码
# 被调用方获取token
String token = CookieUtils.resolveCookie(request, tokenKey);
if (Objects.isNull(token) || token.isBlank()){
    token = request.getHeader(tokenKey);
}
if (Objects.isNull(token) || token.isBlank()){
    token = request.getParameter(tokenKey);
}
return token;

发现被调用方优先从cookie获取代码,未从header获取对应Token;
调用方未设置cookie,怀疑是请求后response缓存带的。增加调用方日志查看

复制代码
log.info("http请求返回,cookie={}", execute.getCookies());


请求返回后在response设置了cookie,但每次请求都是createRequest,理论不会携带cookie。添加disableCookie验证一下:

复制代码
# 创建request增加禁用cookie
HttpRequest request = HttpUtil.createRequest(Method.POST, url);
HttpResponse execute = request
        .disableCookie()
        .addHeaders(headers)
        .timeout(2000)
        .body(JSONUtil.toJsonStr(modelSyncGitDto))
        .execute();

发布后恢复正常,说明请求携带了cookie信息。
后期查看文档hutool的HttpUtil的确有这么一个缓存cookie的问题,参考

https://github.com/dromara/hutool/issues/583

四、梅开二度

  提交代码并告诉测试妹纸"修复好了"。测试验证的确无问题,但遭到测试妹纸的灵魂拷问:
"线上为啥没问题,这次版本不允许夹杂额外代码上线"。
  的确,还是要找到问题的原因。

4.1 配置对比

通过对比线上配置,发现被调用方的common依赖引入了

复制代码
server:
  servlet:
    session:
      # session超时时间,不能小于1分钟
      timeout: 481m
      # 浏览器 Cookie 中 SessionID 名称
      cookie:
        name: Token
        path: /
      tracking-modes: COOKIE

以上配置指定了cookie key为Token,且过期时间为8小时;去掉被调用方以上配置,调用方请求打印cookie如下;
无server.servlet.session配置:

说明被调用方spring security默认会将Cookie设置在当前应用所在的域下放置SESSION。

4.2 二次请求

无server.servlet.session配置:

cookie中返回了SEESION和Token,初步怀疑是缓存返回导致;

4.2 日志对比

相同代码,通过对比其他环境调用方打印的日志,方向无论有无server.servlet.session配置,返回的response都为空

说明还是代码配置问题。

4.3 终极原因

当调用方请求被调用方时,配置的ip不是localhost、127.0.0.1、节点IP时,请求调用返回的response都不会携带cookie。

HttpUtil通过配置请求ip,cookie跨域导致cookie无法保存,也无法携带。
线上httpUtl发起的请求ip为另一台服务器nginx地址,返回的response无cookie。

五、总结

以上问题原因为2个导致:

  1. 本版本hutool的HttpUtil请求缓存了上一次请求的cookie,并在下一次携带;
  2. Spring Security 默认会将Cookie设置在当前应用所在的域下,即localhost。请求方也为localhost所在节点,由于http同源策略,导致返回的response中存在cookie。
相关推荐
深念Y2 天前
AMD 芯片组驱动触发高频 SSD 写入的问题及解决方案
windows·bug·ssd·日志·芯片·驱动·amd
加油码2 天前
探秘 volatile关键字:编译器的过度优化
linux·bug·信号处理
鹿屿二向箔2 天前
keil5.39版本使用AC6编译器不能位域操作的BUG使用STM32U385系列MCU
stm32·单片机·bug
angryshan2 天前
goLang配置断点流程
go·bug
吨吨ai4 天前
# ChatGPT Plus / Pro + Codex Debug 实战:如何让 AI 从日志、Trace、异常堆栈自动定位线上 Bug
人工智能·chatgpt·bug
灰暗世界%4 天前
飞牛bug修复
bug
凌云拓界7 天前
NodeVerdict | 性能门禁:把追踪数据变成 CI 规则
ci/cd·信息可视化·开源·node.js·bug·数据可视化·安全架构
qingmiaozhuan8 天前
软件测试Bug复现高清录屏标准流程:新手入门与规范指南(2026实战版)
bug·电脑录屏·电脑录屏软件·测试录屏规范·音画同步录制
凌云拓界9 天前
NodeVerdict:Node.js 原生诊断数据可视化工具
信息可视化·架构·typescript·开源·node.js·github·bug
蓝天下的守望者13 天前
验证环境中使用队列的pop_front()思维惯性引发的bug
bug