Spring-Cloud-Gateway的413错误解决记录

690 阅读2分钟

问题起因

今天分到一个陈年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)
            )
        );
    }

}

image.png

  • 但是诡异的是,很少有人说明这两种设置的区别和使用场景,也可能是咱水平太低,于是我去扒了一下netty对这两个属性的说明文档

image.png

  • 现在问题就明朗了:
    • 请求行过长就增加maxInitialLineLength
    • 请求头过长就增加maxHeaderSize