Spring Boot
Spring Cloud Gateway
Invalid character ‘[‘ for QUERY_PARAM in “match[]”
1
java.lang.IllegalArgumentException: Invalid character '[' for QUERY_PARAM in "match[]"
Spring Cloud Gateway 与 Webflux 的兼容性的问题,项目的 Gateway 版本 2.0.0.RELEASE,去除
spring-boot-starter-webflux
依赖解决可以升级 Gateway 版本。issuesunexpected message type: DefaultHttpRequest
1
io.netty.handler.codec.EncoderException: java.lang.IllegalStateException: unexpected message type: DefaultHttpRequest
Spring Cloud Gateway 以及 Spring Boot 版本 2.0.1.RELEASE 更新为 2.0.4.RELEASE。issues
Spring MVC
Spring MVC 项目,请求返回 404
Spring Boot 使用惯了,接到 Spring MVC 的反而懵了,在 Controller 中定义好了接口,但是访问就 404。
想到 Spring MVC 的org.springframework.web.servlet.DispatcherServlet
, 于是在 doDispatch() 方法中加上断点进行调试。发现 this.getHandler() 返回了 Null,即 HandlerMapping 为 Null。因为 Controller 中使用了 @RequestMapping 注解,而且项目是使用 XML 的配置方式,所以需要手动配置 RequestMappingHandlerMapping。(如果 Spring MVC 是旧版本也需要手动配置 HandlerAdapter,即对应的 RequestMappingHandlerAdapter)1
2
3
4<!-- 配置 HandlerMapping -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping" />
<!-- 配置 HandlerAdapter -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter" />
Nginx
upstream sent no valid HTTP/1.0 header while reading response header from upstream
Nginx 报错,然后设置了 Nginx 和业务服务配置
1
2
3
4
5
6
7
8
9
10
11proxy_http_version 1.1;
proxy_cache_bypass $http_upgrade;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port $server_port;1
2
3
4
5
6server:
use-forward-headers: true
tomcat:
remote-ip-header: x-forwarded-for
protocol-header: x-forwarded-proto
port-header: X-Forwarded-Port然后依旧报错,此时把服务停止运行再次请求,然而正常访问,说明 Spring Gateway 和 Nginx 之间没有问题,便排查业务服务。
在HandlerInterceptorAdapter
处理拦截器种发现了这么一段代码response.sendError
。
此方法使用指定的状态码发送一个错误响应至客户端。服务器默认会创建一个 HTML 格式的服务错误页面作为响应结果,其中包含参数 msg 指定的文本信息,这个 HTML 页面的内容类型为text/html
,保留 cookies 和其他未修改的响应头信息。
最后去掉此行代码,替换为抛出全局异常,得以解决。1
2
3
4
5public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
***
response.sendError(***);
***
}upstream server temporarily disabled while reading response header from upstream
no live upstreams while connecting to upstream
1
2
3
4
5
6upstream zxjl {
least_conn;
server 192.168.1.1:8765 max_fails=3 fail_timeout=30s;
server 192.168.1.2:8765 max_fails=3 fail_timeout=30s;
keepalive 256;
}max_fails 默认值为 1, fail_timeout 默认值为 10 秒。
fail 失败会返回:
- upstream timed out (110: Connection timed out) while reading response header from upstream
- connect() failed (111: Connection refused) while connecting to upstream
服务器
MySQL
Redis
分布式锁的错误实现
听到同事说到业务加了 Redis 实现的分布式锁,但是没有偶尔没有生效,会重复添加两次数据。查看代码发现大致实现逻辑如下:
1
2
3
4
5if (Boolean.TRUE.equals(redisTemplate.hasKey(key))) {
System.out.println(" 请勿重复提交 ");
return;
}
redisTemplate.opsForValue().set(key, "1", 3, TimeUnit.SECONDS);可以使用 hasKey() 方法来检查 Redis 中是否存在指定的键。但是,在实现分布式锁时,使用 hasKey() 方法并不能保证原子性操作。
考虑以下情况:线程 A 和线程 B 同时调用 hasKey() 方法检查 Redis 是否存在锁键。假设两个线程都发现键不存在,然后都尝试设置锁键。这样就会导致多个线程同时获取到了锁,破坏了锁的互斥性。
为了保证原子性操作,需要使用 Redis 的原子性指令,如 setIfAbsent() 命令。该命令在键不存在时设置键的值,并且保证了原子性操作