081-hutool httputil 集成 sentinel 和 seata

398 阅读1分钟

这是坚持技术写作计划(含翻译)的第81篇,定个小目标999篇。

首先声明,不建议在生产中使用 hutool httputil 因为他没有线程池,性能较差,扩展性差。如果你已经用了 spring boot/ spring cloud 那可以用开箱即用的声明式 http 库,比如 forest 或者 feign , 重度使用的话,可以用老牌的 httpclient 或者 okhttp 等。

但是如果前期团队内部对此没有硬性要求,导致已经已经有历史包袱的情况下,又得上 sentinel 或者 seata 等框架。就得对其进行非侵入式改造了。

Hutool 拦截器

Hutool 5.8.0.M2+ 以后增加了 GlobalInterceptor.addRequestInterceptor、GlobalInterceptor.addResponseInterceptorHttpRequest.addInterceptor 参见 使用hutool的http工具后,如何统一处理Request和Response #2217

记录 httputil 请求日志



@Value("${hutool.http.print-log:false}")
private boolean hutoolHttpPrintLogEnabled;

// 打印 hutool http 请求和响应数据
if (hutoolHttpPrintLogEnabled) {
    GlobalInterceptor.INSTANCE.addRequestInterceptor((req) -> {
        log.info("hutool http 请求 url: {}, method: {}, headers: {}, form: {}, body: {}", req.getUrl(),
            req.getMethod().name(), req.headers(), req.form(), StrUtil.str(req.bodyBytes(), req.charset()));
    });
    GlobalInterceptor.INSTANCE.addResponseInterceptor((resp) -> {
        log.info("hutool http 响应 headers: {}, body: {}", resp.headers(),
            StrUtil.str(resp.bodyBytes(), resp.charset()));
    });
}

集成 seata

@Value("${seata.enabled:false}")
private boolean seataEnabled;

// seata
if (seataEnabled) {
    GlobalInterceptor.INSTANCE.addRequestInterceptor((req) -> {
        req.header(RootContext.KEY_XID, RootContext.getXID());
    });
}

集成 sentinel


@Value("${spring.cloud.sentinel.enabled:false}")
private boolean sentinelEnabled;

// sentinel
if (sentinelEnabled) {
    GlobalInterceptor.INSTANCE.addRequestInterceptor((req) -> {
        try {
            // 抹去参数,只保留 url
            Entry entry = SphU.entry(req.getMethod().name().toUpperCase() + ":"
                + StringUtils.substringBefore(req.getUrl(), "?"));
            ContextUtil.getContext().setCurEntry(entry);
        } catch (BlockException e) {
            log.error("Sentinel 触发流控快速失败", e);
            throw new ApiException("触发流控快速失败");
        }
    });
    GlobalInterceptor.INSTANCE.addResponseInterceptor((resp) -> {
            ContextUtil.getContext().getCurEntry().exit();
    });
}

然后自己写个 configuration 类,把代码塞进去就行了。

招聘小广告

山东济南的小伙伴欢迎投简历啊 加入我们 , 一起搞事情。
长期招聘,Java程序员,大数据工程师,运维工程师,前端工程师。

参考资料