这是坚持技术写作计划(含翻译)的第81篇,定个小目标999篇。
首先声明,不建议在生产中使用 hutool httputil 因为他没有线程池,性能较差,扩展性差。如果你已经用了 spring boot/ spring cloud 那可以用开箱即用的声明式 http 库,比如 forest 或者 feign , 重度使用的话,可以用老牌的 httpclient 或者 okhttp 等。
但是如果前期团队内部对此没有硬性要求,导致已经已经有历史包袱的情况下,又得上 sentinel 或者 seata 等框架。就得对其进行非侵入式改造了。
Hutool 拦截器
Hutool 5.8.0.M2+ 以后增加了 GlobalInterceptor.addRequestInterceptor、GlobalInterceptor.addResponseInterceptor
和 HttpRequest.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程序员,大数据工程师,运维工程师,前端工程师。