文档章节

Tomcat调优之maxHttpHeaderSize设置

十七宝宝
 十七宝宝
发布于 2017/05/31 16:27
字数 1221
阅读 1314
收藏 0

系统中要批量修改N多辆车的车队归属,Request Header无法承载,因此项目中报错:

[http-nio-8081-exec-6] org.apache.coyote.http11.Http11Processor.service Error parsing HTTP request header

Note: further occurrences of HTTP header parsing errors will be logged at DEBUG level.

java.lang.IllegalArgumentException: Request header is too large

at org.apache.coyote.http11.Http11InputBuffer.fill(Http11InputBuffer.java:735)

at org.apache.coyote.http11.Http11InputBuffer.parseRequestLine(Http11InputBuffer.java:497)

at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:667)

at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)

at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:802)

at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1410)

at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)

at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)

at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)

at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)

at java.lang.Thread.run(Thread.java:745)

 

查看对应的类代码,其中涉及的方法如下:

public SocketState process(SocketWrapper<S> socketWrapper) throws IOException { RequestInfo rp = request.getRequestProcessor(); rp.setStage(org.apache.coyote.Constants.STAGE_PARSE); // Setting up the I/O setSocketWrapper(socketWrapper); getInputBuffer().init(socketWrapper, endpoint); getOutputBuffer().init(socketWrapper, endpoint); // Flags keepAlive = true; comet = false; openSocket = false; sendfileInProgress = false; readComplete = true; if (endpoint.getUsePolling()) { keptAlive = false; } else { keptAlive = socketWrapper.isKeptAlive(); } if (disableKeepAlive()) { socketWrapper.setKeepAliveLeft(0); } while (!getErrorState().isError() && keepAlive && !comet && !isAsync() && httpUpgradeHandler == null && !endpoint.isPaused()) { // Parsing the request header try { setRequestLineReadTimeout(); if (!getInputBuffer().parseRequestLine(keptAlive)) { if (handleIncompleteRequestLineRead()) { break; } } if (endpoint.isPaused()) { // 503 - Service unavailable response.setStatus(503); setErrorState(ErrorState.CLOSE_CLEAN, null); } else { keptAlive = true; // Set this every time in case limit has been changed via JMX request.getMimeHeaders().setLimit(endpoint.getMaxHeaderCount()); // Currently only NIO will ever return false here if (!getInputBuffer().parseHeaders()) { // We've read part of the request, don't recycle it // instead associate it with the socket openSocket = true; readComplete = false; break; } if (!disableUploadTimeout) { setSocketTimeout(connectionUploadTimeout); } } } catch (IOException e) { if (getLog().isDebugEnabled()) { getLog().debug( sm.getString("http11processor.header.parse"), e); } setErrorState(ErrorState.CLOSE_NOW, e); break; } catch (Throwable t) { ExceptionUtils.handleThrowable(t); UserDataHelper.Mode logMode = userDataHelper.getNextMode(); if (logMode != null) { String message = sm.getString( "http11processor.header.parse"); switch (logMode) { case INFO_THEN_DEBUG: message += sm.getString( "http11processor.fallToDebug"); //$FALL-THROUGH$ case INFO: getLog().info(message); break; case DEBUG: getLog().debug(message); } } // 400 - Bad Request response.setStatus(400); setErrorState(ErrorState.CLOSE_CLEAN, t); getAdapter().log(request, response, 0); } if (!getErrorState().isError()) { // Setting up filters, and parse some request headers rp.setStage(org.apache.coyote.Constants.STAGE_PREPARE); try { prepareRequest(); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); if (getLog().isDebugEnabled()) { getLog().debug(sm.getString( "http11processor.request.prepare"), t); } // 500 - Internal Server Error response.setStatus(500); setErrorState(ErrorState.CLOSE_CLEAN, t); getAdapter().log(request, response, 0); } } if (maxKeepAliveRequests == 1) { keepAlive = false; } else if (maxKeepAliveRequests > 0 && socketWrapper.decrementKeepAlive() <= 0) { keepAlive = false; } // Process the request in the adapter if (!getErrorState().isError()) { try { rp.setStage(org.apache.coyote.Constants.STAGE_SERVICE); getAdapter().service(request, response); // Handle when the response was committed before a serious // error occurred. Throwing a ServletException should both // set the status to 500 and set the errorException. // If we fail here, then the response is likely already // committed, so we can't try and set headers. if(keepAlive && !getErrorState().isError() && ( response.getErrorException() != null || (!isAsync() && statusDropsConnection(response.getStatus())))) { setErrorState(ErrorState.CLOSE_CLEAN, null); } setCometTimeouts(socketWrapper); } catch (InterruptedIOException e) { setErrorState(ErrorState.CLOSE_NOW, e); } catch (HeadersTooLargeException e) { // The response should not have been committed but check it // anyway to be safe if (response.isCommitted()) { setErrorState(ErrorState.CLOSE_NOW, e); } else { response.reset(); response.setStatus(500); setErrorState(ErrorState.CLOSE_CLEAN, e); response.setHeader("Connection", "close"); // TODO: Remove } } catch (Throwable t) { ExceptionUtils.handleThrowable(t); getLog().error(sm.getString( "http11processor.request.process"), t); // 500 - Internal Server Error response.setStatus(500); setErrorState(ErrorState.CLOSE_CLEAN, t); getAdapter().log(request, response, 0); } } // Finish the handling of the request rp.setStage(org.apache.coyote.Constants.STAGE_ENDINPUT); if (!isAsync() && !comet) { if (getErrorState().isError()) { // If we know we are closing the connection, don't drain // input. This way uploading a 100GB file doesn't tie up the // thread if the servlet has rejected it. getInputBuffer().setSwallowInput(false); } else if (expectation && (response.getStatus() < 200 || response.getStatus() > 299)) { // Client sent Expect: 100-continue but received a // non-2xx final response. Disable keep-alive (if enabled) // to ensure that the connection is closed. Some clients may // still send the body, some may send the next request. // No way to differentiate, so close the connection to // force the client to send the next request. getInputBuffer().setSwallowInput(false); keepAlive = false; } endRequest(); } rp.setStage(org.apache.coyote.Constants.STAGE_ENDOUTPUT); // If there was an error, make sure the request is counted as // and error, and update the statistics counter if (getErrorState().isError()) { response.setStatus(500); } request.updateCounters(); if (!isAsync() && !comet || getErrorState().isError()) { if (getErrorState().isIoAllowed()) { getInputBuffer().nextRequest(); getOutputBuffer().nextRequest(); } } if (!disableUploadTimeout) { if(endpoint.getSoTimeout() > 0) { setSocketTimeout(endpoint.getSoTimeout()); } else { setSocketTimeout(0); } } rp.setStage(org.apache.coyote.Constants.STAGE_KEEPALIVE); if (breakKeepAliveLoop(socketWrapper)) { break; } } rp.setStage(org.apache.coyote.Constants.STAGE_ENDED); if (getErrorState().isError() || endpoint.isPaused()) { return SocketState.CLOSED; } else if (isAsync() || comet) { return SocketState.LONG; } else if (isUpgrade()) { return SocketState.UPGRADING; } else { if (sendfileInProgress) { return SocketState.SENDFILE; } else { if (openSocket) { if (readComplete) { return SocketState.OPEN; } else { return SocketState.LONG; } } else { return SocketState.CLOSED; } } } }

而报错的地方则是在:

// Currently only NIO will ever return false here if (!getInputBuffer().parseHeaders()) { // We've read part of the request, don't recycle it // instead associate it with the socket openSocket = true; readComplete = false; break; } if (!disableUploadTimeout) { setSocketTimeout(connectionUploadTimeout); } 的时候抛出了异常,对应的catch块代码如下: catch (Throwable t) { ExceptionUtils.handleThrowable(t); UserDataHelper.Mode logMode = userDataHelper.getNextMode(); if (logMode != null) { String message = sm.getString( "http11processor.header.parse"); switch (logMode) { case INFO_THEN_DEBUG: message += sm.getString( "http11processor.fallToDebug"); //$FALL-THROUGH$ case INFO: getLog().info(message); break; case DEBUG: getLog().debug(message); } } // 400 - Bad Request response.setStatus(400); setErrorState(ErrorState.CLOSE_CLEAN, t); getAdapter().log(request, response, 0); }

错误日志的输出,是配置在LocalStrings.properties中的,相关的两个属性:

http11processor.fallToDebug=\n Note\: further occurrences of HTTP header parsing errors will be logged at DEBUG level. http11processor.header.parse=Error parsing HTTP request header

找到对应的 getInputBuffer().parseHeaders()

public boolean parseHeaders() throws IOException { if (!parsingHeader) { throw new IllegalStateException( sm.getString("iib.parseheaders.ise.error")); } HeaderParseStatus status = HeaderParseStatus.HAVE_MORE_HEADERS; do { status = parseHeader(); // Checking that // (1) Headers plus request line size does not exceed its limit // (2) There are enough bytes to avoid expanding the buffer when // reading body // Technically, (2) is technical limitation, (1) is logical // limitation to enforce the meaning of headerBufferSize // From the way how buf is allocated and how blank lines are being // read, it should be enough to check (1) only. if (pos > headerBufferSize || buf.length - pos < socketReadBufferSize) { throw new IllegalArgumentException( sm.getString("iib.requestheadertoolarge.error")); } } while ( status == HeaderParseStatus.HAVE_MORE_HEADERS ); if (status == HeaderParseStatus.DONE) { parsingHeader = false; end = pos; return true; } else { return false; } }

可知此处涉及了两个缓冲区大小,headerBufferSize和socketReadBufferSize,如果读取时数据的长度大于这两个值,就会报iib.requestheadertoolarge.error即Request header is too large,在网上搜索时,有的是因为这个设置导致的400,解决方法就是修改Tomcat的server.xml, 在<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />的配置中增加maxHttpHeaderSize的配置

在org.apache.coyote.http11.AbstractHttp11Protocol类中定义了其默认值:

/** Maximum size of the HTTP message header. */ private int maxHttpHeaderSize = 8 * 1024; /** Maximum size of the post which will be saved when processing certain requests, such as a POST. */ private int maxSavePostSize = 4 * 1024; /** * Specifies a different (usually longer) connection timeout during data upload. */ private int connectionUploadTimeout = 300000; /** Maximum size of trailing headers in bytes */ private int maxTrailerSize = 8192; /** Maximum size of extension information in chunked encoding */ private int maxExtensionSize = 8192; /**Maximum amount of request body to swallow.*/ private int maxSwallowSize = 2 * 1024 * 1024;

 

修改Tomcat的server.xml:

<Connector port="8080" protocol="HTTP/1.1"

connectionTimeout="20000"

redirectPort="8443" URIEncoding="UTF-8" maxHttpHeaderSize="1024000"/>

maxHttpHeaderSize修改为合理的大小

注意请求须为POST请求。

© 著作权归作者所有

共有 人打赏支持
十七宝宝
粉丝 0
博文 12
码字总数 6864
作品 0
杭州
程序员
私信 提问
Apache Tomcat 8.5 安全配置与高并发优化

通常我们在生产环境中,Tomcat的默认配置显然不能满足我们的产品需求,所以很多时候都需要对Tomcat的配置进行调优,以下综合我自己的经验来配置 Tomcat 安全与优化情况,如果你有更好的方案,...

Airship
2018/11/19
0
0
tomcat7自身调优和JVM调优

Tomcat优化其实就是对server.xml优化(开户线程池,调整http connector参数) 搜索【<Executor name="tomcatThreadPool"】,开启并调整为 <Executor name="tomcatThreadPool" namePrefix="ca......

蜡笔小小小新
2015/09/07
128
1
tomcat 高流量调优

java 环境配置:export JAVA_OPTS="-server -Xms8g -Xmx8g -Xss128k -XX:ParallelGCThreads=20-XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:SurvivorRatio=8-XX:TargetSurvivorRatio=90 -......

千惊万喜
2016/12/09
26
0
java.lang.IllegalArgumentException: Request header is too large

错误描述: java.lang.IllegalArgumentException: Request header is too large 问题分析: 请求头超过了tomcat的限值。本来post请求是没有参数大小限制,但是服务器有自己的默认大小。 解决...

lyle_luo
2018/12/07
0
0
Tomcat安全优化

开启用户登录失败锁定 路径: /opt/java/tomcat/conf/server.xml 当前值: 加固建议: 检查项: 限制远程管理IP 路径: /opt/java/tomcat/conf/server.xml 当前值: 加固建议: 增加 检查项: 禁止显...

一条特立独行的贪吃蛇
2018/01/06
0
0

没有更多内容

加载失败,请刷新页面

加载更多

查询改写参数配置

参数配置有哪些选项:

Java搬砖工程师
30分钟前
2
0
elasticsearch知识点

elasticsearch基础知识: 基础知识: 1 集群: 主节点不涉及文档级别的变更或搜索 只负责索引的变更 删除 和 集群节点的加入和删除 技术上来说,一个主分片最大能够存储 Integer.MAX_VALUE - 12...

geek土拨鼠
33分钟前
2
0
ECS(Entity-Component-System)

ECS是一种思想 TODO

梦想游戏人
34分钟前
1
0
Navicat使用教程:使用Navicat Premium 12自动执行数据库复制(一)

下载Navicat Premium最新版本 Navicat Premium是一个可连接多种数据库的管理工具,它可以让你以单一程序同时连接到MySQL、Oracle及PostgreSQL数据库,让管理不同类型的数据库更加的方便。 与...

电池盒
35分钟前
4
0
docker 新手向 - 防止容器自动退出的解决方案

本文主要简单介绍 docker 容器与前置进程的关系,以及如何编写 Dockerfile/docker-compose.yml 优雅的让容器可以常驻运行。 docker 容器的生命周期是同容器中的前置进程相关在一起的,这也是...

big_cat
38分钟前
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部