Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”.
After implementing dynamic modifications to the request Body and retrying the request with the Body, we ran into a minor problem. Recently, many interfaces received incorrect parameters. The error reported in the interface layer is:
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"
Copy the code
Error 10#scrollTop=8178
A normal request can be fragment with #. The part after # is fragment. A URI consists of:
For these requests, we found that the original URI of the sent request was encoded with the wrong URL, which became %23. For example, the request above was sent to the back end:
https://[email protected]:8081/test/service?id=test&number=10%23segment1
Copy the code
Number =10#segment1
Because the front-end failed to reproduce the problem, and the problem is concentrated on several browser versions of the system, the problem can only be solved by modifying the background gateway.
Our Gateway is using the Spring Cloud Gateway. We can solve this problem by adding global filters for global requests and dynamically modifying urIs as follows:
@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")) {// Replace %23 with #, Replace ("%23", "#")); replace = new URI(originURIString.replace ("%23", "#")); return chain.filter( exchange.mutate() .request( new ServerHttpRequestDecorator(exchange.getRequest()) { /** * * * @return */ @override public uri getURI() {return press; } @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; }}Copy the code
Points to note are:
- We need to place this Filter at the beginning to ensure that the URI of the subsequent Filter is correct, so that some Filter will not take Fragment as its object.
- If all we care about is that the forwarded request is correct, we simply replace the URI, overriding the getURI method.
- The reason why getQueryParams is overridden is that subsequent filters may also do something to QueryParams, so we want to ensure accuracy.
- Overwriting getQueryParams does not modify QueryParams for subsequent requests forwarded to specific microservices, which can only be modified by overwriting getURI.