【SpringCloud】搭建高可用分布式配置中心(Spring Cloud Config)(二)全过程详解(自动刷新)解决webhooks 400错误
本文基于第一篇搭建好手动刷新的基础上进行的自动刷新。详见(一)全过程详解(手动刷新)。
在搭建好第一步的手动更新的配置中心之后,要实现自动更新就很简单了。
一. config-client添加依赖
pom.xml文件中添加:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
<version>2.0.0.RELEASE</version>
</dependency>
二. 配置文件application.yml文件增加配置
application.yml文件配置:
spring:
rabbitmq:
host: localhost
port: 5672
username: user
password: password
cloud:
bus:
trace:
enabled: true
enabled: true
三. Gitee码云上添加webhooks
需要注意的是:
1.需要有公网ip,码云上需要使用公网ip进行访问(我使用的frp进行的内网穿透,感兴趣的同学可以自己尝试下)
2.访问地址的后缀为 /actuator/bus-refresh
如图所示,即可成功配置。
四.运行即可看到已经自动刷新配置了。
五. ERROR解决
{"timestamp":"2019-01-17T12:33:34.975+0000","status":400,"error":"Bad Request","message":"JSON parse error: Cannot deserialize instance of `java.lang.String` out of START_ARRAY token; nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `java.lang.String` out of START_ARRAY token\n at [Source: (PushbackInputStream); line: 1, column: 326] (through reference chain: java.util.LinkedHashMap[\"commits\"])","path":"/actuator/bus-refresh"}
有不少同学配置之后却无法自动刷新,发现报400 error的错误,如图。
这是因为spring boot无法正常反序列化造成,我们需要写一个过滤器将Body直接返回为空,就可以达到过滤body的效果。
@Component
public class UrlFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest)request;
HttpServletResponse httpServletResponse = (HttpServletResponse)response;
String url = new String(httpServletRequest.getRequestURI());
//只过滤/actuator/bus-refresh请求
if (!url.endsWith("/bus-refresh")) {
chain.doFilter(request, response);
return;
}
//获取原始的body
String body = readAsChars(httpServletRequest);
System.out.println("original body: "+ body);
//使用HttpServletRequest包装原始请求达到修改post请求中body内容的目的
CustometRequestWrapper requestWrapper = new CustometRequestWrapper(httpServletRequest);
chain.doFilter(requestWrapper, response);
}
@Override
public void destroy() {
}
private 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 ? true:false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener readListener) {
}
@Override
public int read() throws IOException {
return byteArrayInputStream.read();
}
};
}
}
public static String readAsChars(HttpServletRequest request)
{
BufferedReader br = null;
StringBuilder sb = new StringBuilder("");
try
{
br = request.getReader();
String str;
while ((str = br.readLine()) != null)
{
sb.append(str);
}
br.close();
}
catch (IOException e)
{
e.printStackTrace();
}
finally
{
if (null != br)
{
try
{
br.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
return sb.toString();
}
}
再次运行项目,测试webhooks,可以发现成功返回
控制台也成功打印出原来的body。
六.总结
很多人没有自动更新的原因可能就是webhooks这边出错,这个方法还是参考的https://blog.****.net/m0_37556444/article/details/82812816,感谢博主,这边写出来大家也一起分享下经验。