Spring MVC: 如何自动生成 RequestID 并在需要时访问 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
feng32
V2EX    程序员

Spring MVC: 如何自动生成 RequestID 并在需要时访问

  •  
  •   feng32 2021 年 2 月 10 日 3083 次点击
    这是一个创建于 1802 天前的主题,其中的信息可能已经有所发展或是发生改变。

    目前的程序结构大概是这样的:

    // base controller 中定义了异常情况下的 API 返回 public class BaseController { @ExceptionHandler(CodeMessageException.class) @ResponseBody protected ResultModel<Long> exception(CodeMessageException e) { log.error("{}", e.getMessage(), e); return new ResultModel<>(e.getCode(), e.getMessage()); } } // 有一个 Filter 已经实现了打印 Request / Response Body (通过 Filter 实现了一些全局的处理逻辑) public class HttpLogFilter implements Filter { @Override public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) { ... } } // 业务 Controller 继承 BaseController @Controller public class DeviceController extends BaseController { @PostMapping("/device/activate") @ResponseBody public ResultModel<Long> activateDevice(@RequestBody ActivateDeviceRequest request) { return deviceService.activateDevice(request.getSn()); } // Service 层可以进行必要的参数检查,然后直接抛一个异常出来 // 异常被 BaseController 捕捉,然后转成 JSON,这样代码看上去就很干净 public ResultModel<Long> activateDevice(String sn) { if (sn == null) { throw new CodeMessageException(ERROR_PARAM_MISSING, "Parameter sn is missing"); } ... } 

    问题来了,现在需要给每个 Request 生成一个 RequestID (UUID),这个 ID 是后端生成的,调用者不需要写对应的代码,但是调用者在 Response 中可以看到这个 Request ID

    如何以尽量小的侵入性实现这个特性呢?基本的需求是 Service 层以及 BaseController (异常处理逻辑) 都能够比较简单地取到这个值并返回

    同时希望打印 Request (包括 url / body)的时候,也能够把 Request ID 打印出来,否则请求量大的时候,日志还是会对不上

    12 条回复    2021-02-12 19:37:04 +08:00
    ltoddy
        1
    ltoddy  
       2021 年 2 月 10 日
    你为什么要在服务端生成啊,不应该是 nginx 或者 api-gateway 那里生成嘛,然后把 request id 透传。
    huifer
        2
    huifer  
       2021 年 2 月 10 日
    spring boot 里面写个 starter 可以吗. 或者引入统一拦截器,或者用 gateway 上面加入这个
    buliugu
        3
    buliugu  
       2021 年 2 月 10 日
    不如老实上一套 APM
    zhiguang
        4
    zhiguang  
       2021 年 2 月 10 日
    requestwrapper
    cs419
        5
    cs419  
       2021 年 2 月 10 日
    生成 reqId:Filter + ThreadLocal
    resp 添加 reqId: HandlerMethodReturnValueHandler
    awm47
        6
    awm47  
       2021 年 2 月 10 日
    之前好像实现过一个,通过声明一个 Request 作用域的 Bean 实现,构造函数里直接随机一个字符串
    clf
        7
    clf  
       2021 年 2 月 10 日
    这个我以前做过,相当于链路追踪用的 ID 呗?

    大致的逻辑给你一个参考:
    1.返回的 response 结构是我自己定义的,里面一个属性是 TraceId 。
    2.然后实现一个 Context 类,见代码片段: https://gist.github.com/lychs1998/1679bc9c155744ba23ea99307244dad8
    3.调用方式就是 TraceContext.ctx.getTraceId();
    4.丢到日志里当一个 TraceId (随意丢不丢,我丢进去是用来链路追踪用的),在需要的时候用 3 里的语句调用就行。

    整体核心就是用好 InheritableThreadLocal 类。
    JohnZorn
        8
    JohnZorn  
       2021 年 2 月 10 日
    filter+threadlocal 保存 id,responsebodyadvice 包装响应
    Geraltt
        9
    Geraltt  
       2021 年 2 月 10 日 via Android
    生成 logId,放到 threadlocal 和 mdc 里面 直接打印,最后包装
    luozic
        10
    luozic  
       2021 年 2 月 11 日 via iPhone
    除了 context 加,也可以通过 jvm 的后门加进去,instrument 机制,不过推荐对接 metrics 架构,可以平滑由日志到 apm 平台。
    samun
        11
    samun  
       2021 年 2 月 12 日
    用的 nginx+lua 处理的
    axbx
        12
    axbx  
       2021 年 2 月 12 日
    filte 添加一个 trace_id,然后从 Context 中获取
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2909 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 34ms UTC 08:51 PVG 16:51 LAX 00:51 JFK 03:51
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86