乐趣区

关于spring-cloud:Spring-Cloud-Gateway-动态修改请求参数解决-URL-编码错误传参问题

Spring Cloud Gateway 动静批改申请参数解决 # URL 编码谬误传参问题

继实现动静批改申请 Body 以及重试带 Body 的申请之后,咱们又遇到了一个小问题。最近很多接口,收到了谬误的参数,在接口层报的错是:

class org.springframework.web.method.annotation.MethodArgumentTypeMismatchException, Failed to convert value of type 'java.lang.String' to required type 'java.lang.Integer'; nested exception is java.lang.NumberFormatException: For input string: "10#scrollTop=8178" 

例如下面这个报错即原本应该是一个数字,后果收到的是 10#scrollTop=8178 导致转换异样。

失常的申请,是能够带 # 的,# 前面的局部属于 fragment。一个 URI 包含:

然而对于这些报错的申请,咱们发现,发送的申请的原始 URI 中,# 被谬误的 URL 编码了,变成了 %23,例如下面的申请,发到后端的是:

https://zhxhash@example.com:8081/test/service?id=test&number=10%23segment1

这样,后端解析到的 number 的值,就是 number=10#segment1,这样就会产生结尾提到的报错。

因为前端没能复现这个问题,并且问题集中于某几个零碎的浏览器版本,这个问题只能通过后盾网关做批改解决。

咱们的网关应用的是 Spring Cloud Gateway,咱们能够针对全局申请增加全局 Filter,动静修改 URI,解决这个问题,代码如下:

@Log4j2
@Component
public class QueryNormalizationFilter implements GlobalFilter, Ordered {
    @Override
    @SneakyThrows
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {String originUriString = exchange.getRequest().getURI().toString();
        if (originUriString.contains("%23")) {
            // 将编码后的 %23 替换为 #,从新用这个字符串生成 URI
            URI replaced = new URI(originUriString.replace("%23", "#"));
            return chain.filter(exchange.mutate()
                            .request(new ServerHttpRequestDecorator(exchange.getRequest()) {
                                        /**
                                         * 这个是影响转发到后盾服务的 uri
                                         *
                                         * @return
                                         */
                                        @Override
                                        public URI getURI() {return replaced;}

                                        /**
                                         * 批改这个次要为了前面的 Filter 获取查问参数是精确的
                                         *
                                         * @return
                                         */
                                        @Override
                                        public MultiValueMap<String, String> getQueryParams() {return UriComponentsBuilder.fromUri(replaced).build().getQueryParams();
                                        }
                                    }
                            ).build());
        } else {return chain.filter(exchange);
        }
    }

    @Override
    public int getOrder() {return Ordered.HIGHEST_PRECEDENCE;}
}

留神点是:

  1. 咱们须要将这个 Filter 放在最开始的地位,保障后续的 Filter 的 URI 是正确的,免得有的 Filter 拿 Fragment 做文章。
  2. 如果咱们只关怀转发的申请是正确的,那咱们只替换 URI 即可,即笼罩 getURI 办法。
  3. 连 getQueryParams 也笼罩的起因,是后续的 Filter 可能也会对 QueryParams 做一些操作,咱们要保障准确性。
  4. 只笼罩 getQueryParams,并不会批改后续转发到具体的微服务的申请的 QueryParams,这个只能通过笼罩 getURI 批改。

微信搜寻“我的编程喵”关注公众号,每日一刷,轻松晋升技术,斩获各种 offer

退出移动版