tomcat请求url过长报400

当GET请求参数达到约1万个字符时,Tomcat抛出HTTP400状态码,原因是maxHttpHeaderSize默认限制为8KB。源码分析表明,参数存储在请求头,超出限制可能导致问题。建议业务上限制输入参数长度或改用POST+FORM请求。另外,socketReadBufferSize和SO_RCVBUF也影响内存分配和TCP接收缓冲区大小。
摘要由CSDN通过智能技术生成

tomcat版本 8.0.49

出现的问题就是GET请求参数特别长,大概有1万个字符,请求的时候出现了HTTP 400的状态码

查了下tomcat的源码和官方文档发现了问题所在

  1. HTTP url后面的参数是放在请求头里面的
  2. tomcathttp connector 有个限制参数 maxHttpHeaderSize : Provides the default value for maxHttpRequestHeaderSize and maxHttpResponseHeaderSize. If not specified, this attribute is set to 8192 (8 KB).

public abstract class AbstractHttp11Protocol<S> extends AbstractProtocol<S> {
    ...

    /**
     * Maximum size of the HTTP message header.
     */
    private int maxHttpHeaderSize = 8 * 1024;
    public int getMaxHttpHeaderSize() { return maxHttpHeaderSize; }
    public void setMaxHttpHeaderSize(int valueI) { maxHttpHeaderSize = valueI; }
    ...
}
  1. tomcat 源码中有个类 AbstractInputBuffer 中存储header的有个字节数组 protected byte[] buf; 这个参数每次解析http请求都会按照配置的 maxHttpHeaderSize + socketReadBufferSize 直接初始化数组长度,并申请内存。
    然后一行一行去解析http的请求头,每行数据都缓存到buf字段里。
    所以这个值不能太大,不建议调整这个参数。比较合理的方案就是业务上限制输入参数的字符长度,超过长度限制则不请求后端接口。如果业务上就是需要这么长的参数,建议转成POST + FORM请求
public abstract class AbstractInputBuffer<S> implements InputBuffer{
    ...
    /**
     * Pointer to the current read buffer.
     */
    protected byte[] buf;
  1. socketReadBufferSize 这个参数,先读取配置 socket.appReadBufSize:(int)Each connection that is opened up in Tomcat get associated with a read ByteBuffer. This attribute controls the size of this buffer. By default this read buffer is sized at 8192 bytes. For lower concurrency, you can increase this to buffer more data. For an extreme amount of keep alive connections, decrease this number or increase your heap size. 如果没有的情况下后读取配置 ,socket.rxBufSize :(int)The socket receive buffer (SO_RCVBUF) size in bytes. JVM default used if not set.
/**
 * Implementation of InputBuffer which provides HTTP request header parsing as
 * well as transfer decoding.
 */
public class InternalNioInputBuffer extends AbstractNioInputBuffer<NioChannel> {

    @Override
    protected void init(SocketWrapper<NioChannel> socketWrapper,
            AbstractEndpoint<NioChannel> endpoint) throws IOException {

        socket = socketWrapper.getSocket();
        if (socket == null) {
            // Socket has been closed in another thread
            throw new IOException(sm.getString("iib.socketClosed"));
        }
        socketReadBufferSize =
            socket.getBufHandler().getReadBuffer().capacity();

        int bufLength = headerBufferSize + socketReadBufferSize;
        if (buf == null || buf.length < bufLength) {
            buf = new byte[bufLength];
        }

        pool = ((NioEndpoint)endpoint).getSelectorPool();
    }
  1. SO_RCVBUF 此参数控制的是操作系统层面每个TCP socket在内核中的接受缓冲区大小
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值