Hutool工具包中HttpUtil的日志统一打印以及统一超时时间配置
作者:mmseoamin日期:2023-12-25

Hutool工具包中HttpUtil的日志统一打印

  • 为何要打印Http请求日志
    • HttpUtil的请求拦截器(HttpInterceptor.Chain)、响应拦截器(HttpInterceptor.Chain
    • HttpUtil的全局日志配置
    • HttpUtil的超时时间源码分析
    • HttpUtil的全局超时时间配置

      为何要打印Http请求日志

      使用hutool工具包中的HttpUtil,为了便于排查问题以及控制请求时间,每次都要在请求前后log日志,每次都需要设置超时时间,十分麻烦。

              log.info("请求路径:{},请求体:{}", url, body);
              HttpResponse response = HttpUtil.createPost(url).body(body).timeout(3000).execute();
              log.info("请求结果:{}", response);
      

      HttpUtil的请求拦截器(HttpInterceptor.Chain)、响应拦截器(HttpInterceptor.Chain)

      从HttpUtil的execute()方法点进去几步,可以看到以下代码

      	/**
      	 * 请求前的拦截器,用于在请求前重新编辑请求
      	 */
      	final HttpInterceptor.Chain requestInterceptors = GlobalInterceptor.INSTANCE.getCopiedRequestInterceptor();
      	/**
      	 * 响应后的拦截器,用于在响应后处理逻辑
      	 */
      	final HttpInterceptor.Chain responseInterceptors = GlobalInterceptor.INSTANCE.getCopiedResponseInterceptor();
      	
      	/**
      	 * 执行Reuqest请求
      	 *
      	 * @param isAsync 是否异步
      	 * @return this
      	 */
      	public HttpResponse execute(boolean isAsync) {
      		return doExecute(isAsync, config.requestInterceptors, config.responseInterceptors);
      	}
      

      这里有两个拦截器配置,分别是请求拦截器配置config.requestInterceptors, 响应拦截器配置config.responseInterceptors

      继续点进去可以看到拦截器的执行逻辑,分别在请求前和请求后执行,代码进行省略,只保留我们需要的逻辑

      	/**
      	 * 执行Reuqest请求
      	 *
      	 * @param isAsync              是否异步
      	 * @param requestInterceptors  请求拦截器列表
      	 * @param responseInterceptors 响应拦截器列表
      	 * @return this
      	 */
      	private HttpResponse doExecute(boolean isAsync, HttpInterceptor.Chain requestInterceptors,
      								   HttpInterceptor.Chain responseInterceptors) {
      		if (null != requestInterceptors) {
      			for (HttpInterceptor interceptor : requestInterceptors) {
      				interceptor.process(this);
      			}
      		}
      		// 初始化URL
      		urlWithParamIfGet();
      		// 初始化 connection
      		initConnection();
      		// 发送请求
      		send();
      		// 手动实现重定向
      		HttpResponse httpResponse = sendRedirectIfPossible(isAsync);
      		// 获取响应
      		if (null == httpResponse) {
      			httpResponse = new HttpResponse(this.httpConnection, this.config, this.charset, isAsync, isIgnoreResponseBody());
      		}
      		// 拦截响应
      		if (null != responseInterceptors) {
      			for (HttpInterceptor interceptor : responseInterceptors) {
      				interceptor.process(httpResponse);
      			}
      		}
      		return httpResponse;
      	}
      

      HttpUtil的全局日志配置

      明白了HttpUtil的execute()方法执行过程,现在我们可以很方便的实现HttpUtil的全局日志了

      项目启动时进行添加我们自定义的拦截器即可,这里直接使用toString方法,是因为HttpUtil里面帮我们重写了toString的逻辑,不需要我们自己去解析HttpRequest和HttpResponse了

          @Autowired
          public void addRequestInterceptor() {
              GlobalInterceptor.INSTANCE.addRequestInterceptor(httpObj -> log.info(String.valueOf(httpObj)));
              GlobalInterceptor.INSTANCE.addResponseInterceptor(httpObj -> log.info(String.valueOf(httpObj)));
          }
      

      HttpUtil的超时时间源码分析

      同样的,我们点进timeout()方法可以发现,会分别设置连接超时、读取响应超时。

      	/**
      	 * 默认连接超时
      	 */
      	int connectionTimeout = HttpGlobalConfig.getTimeout();
      	/**
      	 * 默认读取超时
      	 */
      	int readTimeout = HttpGlobalConfig.getTimeout();
      	/**
      	 * 设置超时,单位:毫秒
      * 超时包括: * *
      	 * 1. 连接超时
      	 * 2. 读取响应超时
      	 * 
      * * @param milliseconds 超时毫秒数 * @return this * @see #setConnectionTimeout(int) * @see #setReadTimeout(int) */ public HttpConfig timeout(int milliseconds) { setConnectionTimeout(milliseconds); setReadTimeout(milliseconds); return this; } /** * 设置连接超时,单位:毫秒 * * @param milliseconds 超时毫秒数 * @return this */ public HttpConfig setConnectionTimeout(int milliseconds) { this.connectionTimeout = milliseconds; return this; } /** * 设置连接超时,单位:毫秒 * * @param milliseconds 超时毫秒数 * @return this */ public HttpConfig setReadTimeout(int milliseconds) { this.readTimeout = milliseconds; return this; }

      但是这两个超时字段配置是由默认的全局配置的。

      所以配置一个全局的超时时间就比较方便了

      HttpUtil的全局超时时间配置

          @Autowired
          public void hutoolHttpUtilConfig() {
              // 设置hutool HttpUtil的request请求参数打印
              GlobalInterceptor.INSTANCE.addRequestInterceptor(httpObj -> log.info(String.valueOf(httpObj)));
              // 设置hutool HttpUtil的response参数打印
              GlobalInterceptor.INSTANCE.addResponseInterceptor(httpObj -> log.info(String.valueOf(httpObj)));
              // 设置hutool HttpUtil的连接超时时间、读取响应超时时间
              HttpGlobalConfig.setTimeout(3000);
          }