spring cloud config bus使用gitLab的webhook出现http 状态码 400 的问题解决方案

lianjin 3月前 40

最近在看SpringCloud的资料 遇到一个 gitlab 的坑


  • 关于 SpringCloud中 使用 spring-cloud-starter-bus-amqp 后可以实现 自动刷新配置

    平时开发可以在浏览器手动访问 /actuator/bus-refresh 请求来实现配置的动态刷新

单如果是当部署到正式环境以后就需要集成webhook

这里我使用的gitlab 的webhook 但是会导致 server config 端 返回的 http状态码为 400 参数解析错误 如下图所示


研究了一下 下面给出一下解决方案 (原理就是 检测到如果访问地址为 刷新配置的接口的时候 把请求内容置空)


  • 在你的 Application 启动类中添加 如下代码

    @Bean
    public FilterRegistrationBean<BodyReaderFilter> filters() {
        FilterRegistrationBean<BodyReaderFilter> registrationBean = new FilterRegistrationBean<>();
        registrationBean.setFilter(new BodyReaderFilter());
        registrationBean.addUrlPatterns("/*");
        registrationBean.setName("requestBodySignFilter");
        registrationBean.setOrder(1);

        Map exclusionsMap = Maps.newHashMap();
        /*
         * 这里排除的东西 是我自己的  你们可以选择删除掉
         */
        exclusionsMap.put(
                "exclusions",
                "/common/upload,/swagger-ui.html,/file/**,/**.js,/**.css,/webjars/**");
        registrationBean.setInitParameters(exclusionsMap);
        return registrationBean;
    }
  • 创建 BodyReaderFilter 类 代码如下 其中 CustometRequestWrapper 的作用 就是 检测到如果是 刷新配置的请求 就把http请求的内容置空 这样就不会服务器解析参数400异常了
    • tip: BodyReaderHttpServletRequestWrapper 是附赠的一个类 可以解决 解决springboot request body 只能读取一次的bug 嘿嘿

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

/**
 * 
 *
 * <p>@Author: 连晋
 *
 * <p>@Description:
 *
 * <p>@email: 832192@qq.com
 *
 * <p>@Source: Created with IntelliJ IDEA. @Data: 10:47
 */
@WebFilter(filterName = "bodyReaderFilter", urlPatterns = "/*")
public class BodyReaderFilter implements Filter {
  private static Logger logger = LoggerFactory.getLogger(BodyReaderFilter.class);

  @Override
  public void init(FilterConfig filterConfig) throws ServletException {}

  @Override
  public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
      throws IOException, ServletException {
    ServletRequest requestWrapper = null;
    if (request instanceof HttpServletRequest) {
      // 只过滤/actuator/bus-refresh请求
      HttpServletRequest httpServletRequest = (HttpServletRequest) request;
      if (httpServletRequest.getRequestURI().endsWith("/bus-refresh")) {
        CustometRequestWrapper noneWrapper = new CustometRequestWrapper(httpServletRequest);
        chain.doFilter(noneWrapper, response);
        return;
      }else {
        requestWrapper = new BodyReaderHttpServletRequestWrapper((HttpServletRequest) request);
      }
    }

    if (requestWrapper == null) {
      chain.doFilter(request, response);
    } else {
      chain.doFilter(requestWrapper, response);
    }
  }

  @Override
  public void destroy() {}
}
  • CustometRequestWrapper 代码如下

import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.ByteArrayInputStream;
import java.io.IOException;

/**
 * 置空 request 请求的传输的数据
 *
 * <p>@Author: 连晋
 *
 * <p>@Description:
 *
 * <p>@email: 832192@qq.com
 *
 * <p>@Source: Created with IntelliJ IDEA. @Data: 10:47
 */
class CustometRequestWrapper extends HttpServletRequestWrapper {
  public CustometRequestWrapper(HttpServletRequest request) {
    super(request);
  }

  @Override
  public ServletInputStream getInputStream() throws IOException {
    byte[] bytes = new byte[0];
    ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);

    return new ServletInputStream() {
      @Override
      public boolean isFinished() {
        return byteArrayInputStream.read() == -1;
      }

      @Override
      public boolean isReady() {
        return false;
      }

      @Override
      public void setReadListener(ReadListener readListener) {}

      @Override
      public int read() throws IOException {
        return byteArrayInputStream.read();
      }
    };
  }
}
  • BodyReaderHttpServletRequestWrapper 代码如下

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StreamUtils;

import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;

/**
 * 解决springboot request body 只能读取一次的bug
 *
 * <p>@Author: 连晋
 *
 * <p>@Description:
 *
 * <p>@email: 832192@qq.com
 *
 * <p>@Source: Created with IntelliJ IDEA. @Data: 10:44
 */
public class BodyReaderHttpServletRequestWrapper extends HttpServletRequestWrapper {
    private static Logger logger = LoggerFactory.getLogger(BodyReaderHttpServletRequestWrapper.class);
    /**
     * 用于将流保存下来
     */
    private byte[] requestBody = null;

    public BodyReaderHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
        super(request);
        requestBody = StreamUtils.copyToByteArray(request.getInputStream());
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {

        final ByteArrayInputStream bais = new ByteArrayInputStream(requestBody);

        return new ServletInputStream() {

            @Override
            public int read() throws IOException {
                return bais.read();
            }

            @Override
            public boolean isFinished() {
                return false;
            }

            @Override
            public boolean isReady() {
                return false;
            }

            @Override
            public void setReadListener(ReadListener readListener) {
            }
        };
    }

    @Override
    public BufferedReader getReader() throws IOException {
        return new BufferedReader(new InputStreamReader(getInputStream()));
    }
}

最终实现效果如图:


最后于 3月前 被lianjin编辑 ,原因:
最新回复 (0)
    • Deep♂Dark♂Fantastic
      2
        立即登录 立即注册 
返回