Tomcat 8.0.11 移动端访问报400错误问题

用java写了一组接口,同时给web,ios,android调用,web端访问正常,但ios访问会报400,打断点进行调试,ios的请求根本都到不了controller的代码中,也就是说在tomcat进行http request解析的时候就报错,并将错误返回给客户端了,具体的错误如下:

01-Dec-2014 11:08:11.688 INFO [http-apr-8080-exec-3] org.apache.coyote.http11.AbstractHttp11Processor.process Error parsing HTTP request header
 Note: further occurrences of HTTP header parsing errors will be logged at DEBUG level.

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

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;

 其他参数设置介绍:http://tomcat.apache.org/tomcat-8.0-doc/config/ajp.html

----------------------------------------分隔线-------------------------------------------------
各种配置尝试后,最终发现问题是因为ios发送http请求时自己添加的User-Agent中的字符编码导致的tomcat在解析http header的时候出错导致的。并非是因为tomcat这边的配置导致的。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: JDBC(Java数据库连接)是Java程序与数据库之间进行交互的重要工具。JDBC 8.0.11是JDBC的一个版本,但在使用过程中,可能会遇到一些常见错误。以下是几种常见的错误: 1. ClassNotFoundException(类未找到异常):这通常是由于未找到JDBC驱动程序引起的。在使用JDBC时,需要确保正确配置了驱动程序的类路径,并且驱动程序的jar文件已经导入到项目中。 2. SQLException(SQL异常):这是由于SQL语句执行或连接数据库过程中出现的问题。常见的原因有:错误的SQL语法、连接数据库时的用户名或密码错误、数据库服务器关闭等。在遇到SQLException时,我们需要仔细检查SQL语句的正确性,并确保数据库连接参数的正确性。 3. ConnectException(连接异常):这是由于无法连接到数据库服务器引起的。可能的原因包括:数据库服务器地址或端口号配置错误、网络连接故障、数据库服务器未启动等。在遇到连接异常时,我们需要确保数据库服务器处于正常运行状态,并检查连接参数的准确性。 4. DataConversionException(数据转换异常):这是由于数据类型转换错误引起的。在使用JDBC时,Java和数据库之间的数据类型需要正确匹配。在进行数据操作时,需要确保正确的数据类型转换,以避免此类异常。 5. BatchUpdateException(批处理异常):这是由于批处理操作中某一项失败,导致整个批处理操作失败引起的。在进行批处理操作时,需要逐一检查每一条SQL语句的执行结果,并处理其中的异常情况。 总之,JDBC 8.0.11在使用过程中可能会遇到上述常见错误,我们需要仔细检查代码、确保配置正确、处理异常情况,以保证程序与数据库的正常交互。 ### 回答2: JDBC 8.0.11Java数据库连接(JDBC)的一个版本,用于在Java程序和数据库之间进行通信。在使用这个版本时,可能会遇到一些常见的错误。下面是一些可能会出现的错误和解决方法: 1. ClassNotFoundException:这个错误通常发生在Java程序无法找到JDBC驱动程序时。解决方法是确保已经将JDBC驱动程序的jar文件添加到项目的类路径中。 2. SQLException:这是一个在与数据库交互时常见的错误。这个错误可能会发生在连接数据库、执行查询或更新语句时。解决方法是检查数据库连接URL、用户名和密码是否正确,并确保数据库服务器运行正常。 3. NullPointerException:这个错误通常表示代码中的空指针引用。在使用JDBC时,可能会发生这个错误,比如在尝试使用已关闭的连接或未初始化的变量时。解决方法是仔细检查代码并确保所有的对象都被正确地初始化和关闭。 4. BatchUpdateException:在批量执行更新操作时可能会出现这个异常。这个异常表示在执行一批更新语句时,其中一个或多个语句执行失败。解决方法是检查每个更新语句的语法和逻辑,并确保它们正确地执行。 5. DataTruncation:这个异常通常发生在尝试将数据插入到字段中,而字段长度不足以容纳该数据。解决方法是检查数据库表结构的设计,并确保字段长度足够容纳所需的数据。 这些是一些JDBC 8.0.11常见的错误和解决方法。当使用JDBC时,遇到错误是很常见的,但通过仔细检查和调试代码,可以很容易地解决这些问题,并确保与数据库的正常通信。 ### 回答3: JDBC 8.0.11Java连接数据库的一个版本,虽然它相对较新,但仍然有一些常见的错误可能发生。以下是几个常见的错误以及可能的解决方案: 1. ClassNotFoundException:这个错误意味着无法找到指定的JDBC驱动程序。解决方法是检查你的类路径中是否包含正确的驱动程序JAR文件,并确保在连接数据库之前加载驱动程序。 2. SQLException:这个错误通常表示在执行SQL查询或更新时出现问题。可能的原因包括SQL语句的语法错误、无效的表或列名称以及数据库连接问题。为了解决这个问题,首先检查你的SQL语句的正确性,并确保数据库连接的可用性。 3. ConnectionTimeoutException:这个错误意味着连接数据库的超时时间已过。这可能是由于网络问题、数据库服务器负载过高或数据库连接池配置不正确等原因引起的。要解决这个问题,可以尝试增加连接超时时间,并确保数据库服务器的正常运行。 4. IntegrityConstraintViolationException:这个错误意味着在数据库表中违反了完整性约束,例如主键或唯一键冲突。解决这个问题的方法是检查数据插入或更新的值是否满足表中的约束条件,并确保只插入或更新有效的数据。 5. ResultSetClosedException:这个错误意味着试图访问一个已经关闭的结果集。解决这个问题的方法是确保在使用结果集之前,通过调用关闭方法来正确地关闭结果集。 总之,理解和解决这些常见错误能够帮助开发人员更好地使用JDBC 8.0.11连接数据库,并减少潜在的错误和问题
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值