tomcat请求url过长报400

tomcat版本 8.0.49

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

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

  1. HTTP url后面的参数是放在请求头里面的
  2. tomcat 的 http 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在内核中的接受缓冲区大小

 

解决Springboot get请求是参数过长的情况

 

解决Springboot get请求是参数过长的情况

问题原因

Springboot get请求是参数过长抛出异常Request header is too large 的问题

错误描述

java.lang.IllegalArgumentException: Request header is too large

解决方案

请求头超过了tomcat的限值。本来post请求是没有参数大小限制,但是服务器有自己的默认大小。

设置服务器大小:

1.普通tomcat

server.xml

 <Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443" maxPostSize="0" maxHttpHeaderSize ="102400"/>

处加上

 maxHttpHeaderSize =”102400”

2.SpringBoot

SpringBoot项目更方便了,在application.properties文件中添加

#请求参数过长设置

server.max-http-header-size=102400

补充知识:JavaWeb - URL 中很长的一串请求参数,为什么不采用 POST 方式?

GET 方法

请注意,查询字符串(名称/值对)是在 GET 请求的 URL 中发送的:

/test/demo_form.asp?name1=value1&name2=value2

有关 GET 请求的其他一些注释:

GET 请求可被缓存

GET 请求保留在浏览器历史记录中

GET 请求可被收藏为书签

GET 请求不应在处理敏感数据时使用

GET 请求有长度限制

GET 请求只应当用于取回数据

POST 方法

请注意,查询字符串(名称/值对)是在 POST 请求的 HTTP 消息主体中发送的:

POST /test/demo_form.asp HTTP/1.1

Host: w3schools.com

name1=value1&name2=value2

有关 POST 请求的其他一些注释:

POST 请求不会被缓存

POST 请求不会保留在浏览器历史记录中

POST 不能被收藏为书签

POST 请求对数据长度没有要求

小雷FansUnion

get方式,是浏览器默认方式,访问简单,比如点击一个链接,直接就跳转了。

如果用post,还需要构造表单,程序实现麻烦,用户体验还会收到“不能重复提交表单”等提示,麻烦很多。

get方式,用户直接看到url和参数,复制粘贴,可以方便收藏、转发,而post不行。

网友看法 - 方腾飞

这个原因很多。在很多场景下,用GET实现起来更简单,也足够了,比如并发网给其他网站引流需要加些参数,这样方便其他网站统计流量来源,如果用POST,并发网就的做一个Post提交,会比较麻烦。

割眼看世界

浏览器地址栏打开的默认就是GET,所以链接用GET很方便。

POST的提交需要表单或js提交,麻烦。

GET可以使用缓存。

华仔的逆袭

Get方式的简洁和缓存比较能说服我。

如何处理Get请求参数过长

1.项目中总会遇到一些get请求参数过长,导致访问失败的问题,首先,get请求参数过长,访问失败的原因不是http协议的限制,是浏览器与服务器对get请求长度限制导致的。

2.常见的浏览器get请求方式长度限制

Http get方法提交的数据大小长度并没有限制,Http协议规范没有对URL长度进行限制。

       目前说的get长度有限制,是特定的浏览器及服务器对它的限制。

        各种浏览器和服务器的最大处理能力如下:

        IE:对URL的最大限制为2083个字符,若超出这个数字,提交按钮没有任何反应。

        Firefox:对Firefox浏览器URL的长度限制为:65536个字符。

        Safari:URL最大长度限制为80000个字符。

        Opera:URL最大长度限制为190000个字符。

        Google(chrome):URL最大长度限制为8182个字符。

        Apache(Server):能接受的最大url长度为8192个字符(这个准确度待定???)

        Microsoft Internet Information Server(IIS):n能接受最大url的长度为16384个字符。

 

3.适用场景:在有些项目中需要签署一些买卖合同协议,合同内容有些值是不固定的,比如说地址,日期等,这些不固定的值可能有上百个,如果用户需要查看协议内容,一般会打开一个新的页面。这时需要将这些不固定的值填充到协议页面上。

4.如果直接使用get传输所有参数 方式打开新页面

 window.open(baseUrl+"/mercAxqSign?param="+param,"_blank");

param做为一个json字符串,可能包含上百个参数,这时会请求出错。

5,处理方式 :通过post请求解决get请求参数过长

先通过post请求,将参数存到后台服务中,如果参数比较重要,可以保存到数据库中,如果不重要,就放在缓存中,五分钟后自动清空。

 
  1. $.ajax({
  2. url: baseUrl+"/yplay/axq_save_params", //这里保存参数信息
  3. type: "post", // 提交方式
  4. contentType : "application/json",
  5. data: JSON.stringify(params), // data为String类型,必须为 Key/Value 格式。
  6. dataType: "json", // 服务器端返回的数据类型
  7. async:false,
  8. success: function (data) {
  9. if (data.code == "000000") {
  10. if(freezeVersion == "0"){
  11. window.open(baseUrl+"/mercAxqSign?id="+id,"_blank"); //通过id去服务器端查找参数
  12. } else{
  13. window.open(baseUrl+"/mercAxqProtocol?id="+id,"_blank");
  14. }
  15.  
  16.  
  17. } else {
  18. alert(data.message);
  19. }
  20. },
  21. });
 

服务器端代码,这里使用的jsp页面,返回ModelAndView:

 
  1. @RequestMapping(value ="/mercAxqSign")
  2. public ModelAndView mercAxqSign(HttpServletRequest request) {
  3. String id = (String) request.getParameter("id");
  4. String data = jinJianService.axqGetParams(id); //通过id查询保存到数据库的参数
  5. ModelAndView mv = new ModelAndView();
  6. mv.addObject("data",JSONObject.parse(data));
  7. mv.setViewName("mercAxqSign");
  8. return mv;
  9. }
 

 

posted @ 2024-12-12 10:36  CharyGao  阅读(33)  评论(0编辑  收藏  举报