Spring Cloud Gateway 動態修改請求參數解決 # URL 編碼錯誤傳參問題
- 2021 年 10 月 5 日
- 筆記
- Spring Cloud, Spring Cloud 全解, Spring Cloud 升級之路
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,例如上面的請求,發到後端的是:
//[email protected]: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;
}
}
注意點是:
- 我們需要將這個 Filter 放在最開始的位置,保證後續的 Filter 的 URI 是正確的,以免有的 Filter 拿 Fragment 做文章。
- 如果我們只關心轉發的請求是正確的,那我們只替換 URI 即可,即覆蓋 getURI 方法。
- 連 getQueryParams 也覆蓋的原因,是後續的 Filter 可能也會對 QueryParams 做一些操作,我們要保證準確性。
- 只覆蓋 getQueryParams,並不會修改後續轉發到具體的微服務的請求的 QueryParams,這個只能通過覆蓋 getURI 修改。
微信搜索「我的編程喵」關注公眾號,每日一刷,輕鬆提升技術,斬獲各種offer: