问题起因
今天分到一个陈年BUG,前端使用一个接口传递过多参数(100个32字节的ID信息)时,返回413 Request Entity Too Large错误
BUG排查
-
查看响应状态码,发现前端发出的居然是Get请求,且所有参数都拼接到url请求行上。
-
查看后端代码后,我发现这个接口接受参数使用的数据结构
hashmap,导致url中存在大量重复的key值,最大100条数据拼接出的url请求大小达到了7k左右。然而由于关联的API过多,修改请求方式工作量过大,pass。 -
既然不能改接口,那就只好增加配置,好在这借口由于分页大小的限制,最大也就是100个参数,顶天不过7000多个字节,现代浏览器的get请求行长度限制都普遍在8k以上,客户端问题不大,只要增加服务器的配置就可以了
BUG解决
-
由于项目使用
nginx做中转,所以首先想到增加nginx的Nginx中的【client_max_body_size】配置属性,但是很可惜测试仍返回413错误(后来我想起来nginx的client_max_body_size默认值就有1MB,完全可以满足这点要求,nginx的这个属性更多会应用在解除上传大文件限制的场景) -
nginx没问题的话,接着排查就得是
Gateway,查看运行日志很顺利的发现HTTP对GET请求的头大小进行了限制【4096字节】导致的问题 -
就当我开开心心去StackFlow查解决方案的时候,我发现这问题早在18年就有人发在
Spring-Cloud-Gateway的issue下面了,而且解决方法很简单:只需要在使用Netty配置类实现WebServerFactoryCustomizer接口重写customize(NettyReactiveWebServerFactory container)方法来增加Gateway的最大请求限制。 -
不出意外的话,意外就出来了
-
在GitHub和各个博客,对于此问题分成了两派,一派增加
httpRequestDecoder的最大请求头大小maxHeaderSize,另一派则主张增加最大请求行maxInitialLineLength。
/** 增加网关的maxHeaderSize属性 */
@Component
public class CustomizeNetty implements WebServerFactoryCustomizer<NettyReactiveWebServerFactory> {
@Value("${server.max-http-header-size:65536}")
private int maxHeaderSize;
public void customize(NettyReactiveWebServerFactory container) {
container.addServerCustomizers(
httpServer -> httpServer.httpRequestDecoder(
httpRequestDecoderSpec -> httpRequestDecoderSpec.maxHeaderSize(maxHeaderSize)
)
);
}
}
@Component
public class NettyConfiguration implements WebServerFactoryCustomizer<NettyReactiveWebServerFactory> {
@Value("${server.max-initial-line-length:65536}")
private int maxInitialLingLength;
public void customize(NettyReactiveWebServerFactory container) {
container.addServerCustomizers(
httpServer -> httpServer.httpRequestDecoder(
httpRequestDecoderSpec -> httpRequestDecoderSpec.maxInitialLineLength(maxInitialLingLength)
)
);
}
}
- 但是诡异的是,很少有人说明这两种设置的区别和使用场景,也可能是咱水平太低,于是我去扒了一下netty对这两个属性的说明文档
- 现在问题就明朗了:
- 请求行过长就增加
maxInitialLineLength - 请求头过长就增加
maxHeaderSize
- 请求行过长就增加