• 【解决问题思路分析】记录hutool默认使用服务端上次返回cookie的问题解决思路


    背景:

    本服务需要调用第三方接口获取数据,首先调用public-key接口获取公钥,然后用公钥加密密码,将用户名和密码传入/ticket接口,获取Cookie和response body中的token。
    请添加图片描述

    排查思路

    由于是调用第三方接口出现问题,第一步先拉通第三方对接人查看后台日志,对方使用apisix作为api网关,初步判断是对方有不同节点,负载均衡到不同节点而导致的偶发性问题。因此本地使用postman连续发起多次请求,经过50次请求后,每一次都能正确响应结果,此时可推测应该不是由于负载均衡不同节点导致的。

    思路二:既然postman每次都能成功,业务系统却会偶发性,说明问题应该是出在本地代码。Debug本地调用流程以期望能够复现302问题,经过多次运行发现,第三方接口返回的cookie和token(下面将cookie和token统称为凭证)会存储在redis中。

    代码中判断如果redis中没有凭证,则会重新获取并保存在redis中,如果redis中有凭证则从redis中获取。而redis中没有凭证时,调用第三方接口就获取凭证,再调用第三方业务接口时就一定会报错302,若直接从redis中获取凭证则不会有该问题。此时,可以复现302问题。

    既然从redis中获取是正确的,而第一次请求过来就是302错误,我们对比两者的凭证,发现凭证时一模一样的。此时和对接人讨论,怀疑可能第是三方bug:在第一次请求时会查找本地缓存凭证,如果没有的话,则报错302,第二次就能在缓存中找到。为了验证该假设,我们用postman去做第一次调用,发现postman在第一次调用也是能够正常返回的,此时陷入僵局。

    思路三:此时,想到通过wireShark抓包查看本地发出的请求有什么区别,但由于是https请求,却看不到header信息。

    思路四:由于我们能准确复现302问题,我们再次拉通第三方,期望从对方日志中发现异常,从日志中发现,我们传过去的header中有两个cookie,但是我们代码中只传了一个cookie,此时推测可能是hutool在第一次获取服务端请求时把Cookie缓存起来,下次调用就默认带上Cookie。

    HttpRequest req = HttpUtil.createRequest(Method.GET, url) 
    							.header("Content-Type", MediaType.APPLICATION_JSON_VALUE)  
    							  .header("Cookie", "Cookie")     
    							  .header("CSRFPreventionToken", "CSRFPreventionToken") 
    							  .header("client_token", "client_token");
    HttpResponse response =req.execute();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    因此我们使用Apache来调用验证,发现Apache调用并不会出现302问题,此时可确认该问题是由于hutool工具会缓存Cookie,经过debug,发现确实会缓存到threadLocal中。最终,通过在调用/ticket接口并获取完数据后,加上下面一行代码解决。

    HttpRequest.getCookieManager().getCookieStore().removeAll();
    
    • 1

    问题原因

    hutool 自动保存了我们 /ticket 返回的 cookie,在这我们重新设置了一遍 token、cookie,导致重复了;然后为什么第二次访问没问题,第一次的request已经结束了,Cookie也就被清掉了,所以只有我们设置的token、Cookie。

    总结

    本次问题的解决最终找到hutool缓存上一次服务端返回的Cookie是不容易的,中间甚至还用抓包解决,这些解决思路值得记录。通过复盘分析, wireShark是个很好的定位问题工具,需要花点时间学习;开源包的issue是个解决问题的好思路,可以在上面搜索一下;当然还有复现问题,第三方协助,这些都很重要。

    最后感谢自己,絮絮叨叨完成了博客,期待写出更多博客哦

    参考博客

    https://github.com/dromara/hutool/issues/583
    https://blog.csdn.net/weixin_30315905/article/details/97599019

  • 相关阅读:
    cpu门禁电梯卡复制测试过程
    umi-request & useRequest 源码分析及业务实践
    让我们重新认识一下docker 的全局观
    Java注解@PostConstruct使用及相关原理分析
    HCIA-综合实验(三)
    NPS:使用 Windows NPS Server 部署 802.1X 无线认证(4)
    NanoPC-T4 RK3399:移植Kernel和rootfs
    《Python趣味工具》——自制emoji3
    R可视化:单细胞常用的降纬图
    动态链接库(七)--解决不同调用约定导致的名字改编问题
  • 原文地址:https://blog.csdn.net/xjw9602/article/details/133741104