title: “SpringCloud + SpringGateway 解決Get請(qǐng)求傳參為特殊字符導(dǎo)致400無法通過網(wǎng)關(guān)轉(zhuǎn)發(fā)的問題”
createTime: 2021-11-24T10:27:57+08:00
updateTime: 2021-11-24T10:27:57+08:00
draft: false
author: “Atomicyo”
tags: [“tomcat”]
categories: [“java”]
description: “SpringCloud + SpringGateway 解決Get請(qǐng)求傳參為特殊字符導(dǎo)致400無法通過網(wǎng)關(guān)轉(zhuǎn)發(fā)的問題”
SpringCloud + SpringGateway 解決Get請(qǐng)求傳參為特殊字符導(dǎo)致400無法通過網(wǎng)關(guān)轉(zhuǎn)發(fā)的問題
場(chǎng)景:
公司以前的框架統(tǒng)一使用Post請(qǐng)求,傳入?yún)?shù)為一個(gè)定義的公共類,類里面有個(gè)String類型的bean字段傳入json字符串作為傳參,emmm就想給他改成restful風(fēng)格,在傳入?yún)?shù)公共類無法改變的情況下,Get請(qǐng)求會(huì)傳入特殊字符,導(dǎo)致400錯(cuò)誤。例如:
localhost:10001/verify/compreport/month?data={"compRefOwid":"1448487922485252098", "yhMonth":"2021-10"}
原因:
Tomcat的新版本中增加了一個(gè)新特性,就是嚴(yán)格按照 RFC 3986規(guī)范進(jìn)行訪問解析,而 RFC 3986規(guī)范定義了Url中只允許包含英文字母(a-zA-Z)、數(shù)字(0-9)、-_.~4個(gè)特殊字符以及所有保留字符(RFC3986中指定了以下字符為保留字符:! * ’ ( ) ; : @ & = + $ , / ? # [ ])。
解決方案選擇:
- 前端請(qǐng)求時(shí)encode特殊字段(算了,不能因?yàn)樽约旱脑蚣哟笄岸斯ぷ髁?
- 改用post請(qǐng)求(emmm沒有辦法的辦法,看著難受就是想要改了)
- 改Tomcat配置文件(由于是springboot項(xiàng)目,內(nèi)嵌了tomcat,不方便修改,好吧就是我比較菜)
- 在后端代碼層面解決這個(gè)問題
解決方法:
其他服務(wù):由于使用的是內(nèi)嵌的tomcat,網(wǎng)上常見的
解決spring boot請(qǐng)求包含非法字符問題 The valid characters are defined in RFC 7230 and RFC 3986 錯(cuò)誤
配置TomcatServletWebServerFactory的方式使用時(shí)會(huì)導(dǎo)致兩個(gè)TomcatServletWebServerFactory使springboot項(xiàng)目報(bào)錯(cuò)Unable to start ServletWebServerApplicationContext due to multiple ServletWebServerFactory beans而無法啟動(dòng)。而使用yml配置的方式也無法生效。
server:
tomcat:
relaxed-query-chars:
- "<"
- ">"
- "["
- "]"
- "{"
- "}"
隨后參考了繼承WebServerFactoryCustomizer的方式來修改Tomcat配置
SpringBoot2.0.0新版本內(nèi)嵌Tomcat配置
import org.springframework.boot.context.properties.PropertyMapper;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.stereotype.Component;
/**
* Tomcat配置
* @author Atomicyo
* @version 1.0
createTime: 2021-11-24T10:27:57+08:00
updateTime: 2021-11-24T10:27:57+08:00
*/
@Component
public class MyTomcatWebServerCustomize implements WebServerFactoryCustomizer<TomcatServletWebServerFactory> {
private int maxParameterCount = 10000;
@Override
public void customize(TomcatServletWebServerFactory factory) {
PropertyMapper propertyMapper = PropertyMapper.get();
propertyMapper.from(this::getMaxParameterCount)
.when(v -> true)
.to(v -> customizerProperty(factory));
}
/**
* params特殊字符過濾
* @param factory
* @return void
* @author Atomicyo
createTime: 2021-11-24T10:27:57+08:00
updateTime: 2021-11-24T10:27:57+08:00
* @version 1.0
*/
private void customizerProperty(TomcatServletWebServerFactory factory) {
factory.addConnectorCustomizers(
connector -> connector.setProperty("relaxedQueryChars", "[]{}"));
}
public void setMaxParameterCount(int maxParameterCount) {
this.maxParameterCount = maxParameterCount;
}
public int getMaxParameterCount() {
return maxParameterCount;
}
}
網(wǎng)關(guān)模塊:
由于spring gateway使用的是netty作為服務(wù)。所以修改tomcat配置的方式無法生效。參考Spring Cloud Gateway 和 Webflux 請(qǐng)求參數(shù)非法字符處理文章來源:http://www.zghlxwxcb.cn/news/detail-727794.html
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.codec.http.HttpRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.web.embedded.netty.NettyReactiveWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.stereotype.Component;
import reactor.netty.ConnectionObserver;
import reactor.netty.NettyPipeline;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
/**
* Netty編碼配置
* @author Atomicyo
* @version 1.0
createTime: 2021-11-24T10:27:57+08:00
updateTime: 2021-11-24T10:27:57+08:00
*/
@Component
@Slf4j
public class EncodeQueryNettyWebServerCustomizer implements WebServerFactoryCustomizer<NettyReactiveWebServerFactory> {
/**
* 需要encode的特殊字符
*/
private final List<Character> charList = new ArrayList<Character>() {
{
this.add('{');
this.add('}');
this.add('[');
this.add(']');
}
};
@Override
public void customize(NettyReactiveWebServerFactory factory) {
factory.addServerCustomizers(httpServer ->
httpServer.observe((conn, state) -> {
if (state == ConnectionObserver.State.CONNECTED) {
conn.channel().pipeline().addAfter(NettyPipeline.HttpCodec, "", new QueryHandler());
}
}));
}
class QueryHandler extends ChannelInboundHandlerAdapter {
public QueryHandler() {
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws UnsupportedEncodingException {
if (msg instanceof HttpRequest) {
HttpRequest request = (HttpRequest) msg;
String url = request.uri();
// fix url
log.info("url: {}", url);
String[] split = url.split("\\?");
StringBuilder fixUrl = new StringBuilder(split[0]);
if (split.length > 1) {
fixUrl.append("?");
char[] chars = split[1].toCharArray();
for (char aChar : chars) {
if (charList.contains(aChar)) {
fixUrl.append(URLEncoder.encode(String.valueOf(aChar), "UTF-8"));
}else {
fixUrl.append(aChar);
}
}
}
log.info("fixUrl: {}", fixUrl);
request.setUri(fixUrl.toString());
}
ctx.fireChannelRead(msg);
}
}
}
驗(yàn)證:
文章來源地址http://www.zghlxwxcb.cn/news/detail-727794.html
到了這里,關(guān)于SpringCloud + SpringGateway 解決Get請(qǐng)求傳參為特殊字符導(dǎo)致400無法通過網(wǎng)關(guān)轉(zhuǎn)發(fā)的問題的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!