Tomcat 中 HTTP 400 Bad Request 的常见原因以及示例 | 您所在的位置:网站首页 › tomcat运行日志在哪 › Tomcat 中 HTTP 400 Bad Request 的常见原因以及示例 |
背景
在web开发中, HTTP 400 Bad Request 是一种常见但却难以定位的问题, 通常是因为请求没有遵循 HTTP 标准. 原因看起来很直观, 但是在定位此类问题时, 往往需要花费极大的精力. 有以下几个难点: 一个请求在从客户端发出到应用服务器收到这个过程中, 中间经历了各种转发, 每个中间环节都有可能对请求进行改写, 例如代理、LB等. 所以通常需要与多个部门沟通协作, 定位改动发生的环节. 当不满足HTTP 标准的请求到达应用服务器之后, Tomcat 会在请求进入业务逻辑之前就返回400, 并且对于这种行为的默认的日志等级为debug. 这就意味着, 当此类问题发生时, 从业务逻辑的日志中发现不了任何异常. 通常需要抓包或暂时将Tomcat 的日志标准设置为debug. 即使抓包获取了请求信息, 也很难直接观察出请求出问题的地方. 甚至有些情况下, “相同”的请求, 一部分没有问题, 另一部分有问题. 这给定位问题带来了更多的干扰项.在本片文章中, 会分享实际生产环境下的真实事例. 并且对Tomcat中所有400的情况给出了实际例子, 方便以后更直观的判断请求是否有问题. 本文基于 tomcat-embed-core-9.0.29 案例分析 Case 1. Web容器使用的协议版本不同详见下一篇博文 Case 2. 请求头中含有非法字符 现象由于对LB进行升级, 将流量从旧的LB切换到新的LB之后, 某些客户端的所有响应都变成了 400 BAD REQUEST. 分析切换前后的网络拓扑结构发生了变化: 切换之前, 请求路线为 client -> 旧LB -> proxy -> server 切换之后, 请求路线为 client -> 新LB -> server proxy 做了一些额外的操作来确保请求的正确性. 在这里, 它将请求头中冒号前的空格给删除了.请求头中冒号前的空格属于非法字符, Tomcat对于这种情况会直接返回400. 客户端发送的请求头示例 "APPLICATION-VERSION : 519", 冒号前的空格即为非法字符. Tomcat相关源码Tomcat调用逻辑如下. 在parseHeader()方法中, 会使用isToken()方法检查请求头中是否有非法字符. org.apache.coyote.http11.Http11Processor#service org.apache.coyote.http11.Http11InputBuffer#parseHeaders org.apache.coyote.http11.Http11InputBuffer#parseHeader org.apache.tomcat.util.http.parser.HttpParser#isToken org.apache.coyote.http11.Http11InputBuffer#skipLine throw new IllegalArgumentException(message); response.setStatus(400);org.apache.coyote.http11.Http11Processor#service: parseHeaders and catch IllegalArgumentException imageorg.apache.coyote.http11.Http11InputBuffer#parseHeader: 检验请求头并在skipLine()中抛出llegalArgumentException. IS_TOKEN 是一个用来存储非法字符的位图, 非法字符包含 ' ' ',' '(' ')' '' 等. imageorg.apache.coyote.http11.Http11InputBuffer#skipLine: 抛出异常 image Tomcat HTTP 400 Bad Request总结 * Guide这里总结了所有tomcat-embed-core-9.0.29中会返回HTTP 400 Bad Request的情况, 并给出了样例. 以下例子均为HTTP报文格式, case 0 是一个可以正确返回200的请求, 后续的例子是在case 0 的基础上进行改变, 改变的部分会以橙色标出, 导致400的关键字会以红色标出, 便于直观的发现问题. 0. 正确的请求200 Sample Host: localhost Content-Type: application/xml X-SOA-OPERATION-NAME: getVersion\r\n\tsecond line\r\n\tthird line X-SOA-SERVICE-NAME: CoreShippingService Content-length: {requestBodyLength}200 Sample Host: localhost Content-Type: application/xml X-SOA-OPERATION-NAME: getVersion\r\n\tsecond line\r\n\tthird line X-SOA-SERVICE-NAME: CoreShippingService Content-length: {requestBodyLength} 1. 请求头Host中端口号不为数字org.apache.coyote.AbstractProcessor#line 302 400 Sample Host: localhost:abc Content-Type: application/xml X-SOA-OPERATION-NAME: getVersion\r\n\tsecond line\r\n\tthird line X-SOA-SERVICE-NAME: CoreShippingService Content-length: {requestBodyLength} 2. 请求头Host中含有非法字符org.apache.coyote.AbstractProcessor#line 337 Illegal characters logic: org.apache.tomcat.util.http.parser.HttpParser.DomainParseState#next 400 Sample Host: localho(st Content-Type: application/xml X-SOA-OPERATION-NAME: getVersion\r\n\tsecond line\r\n\tthird line X-SOA-SERVICE-NAME: CoreShippingService Content-length: {requestBodyLength} 3.Socket状态为CONNECT_FAIL(eg. TLS handshake FAIL)org.apache.coyote.AbstractProcessor#line 982 No example 4. 请求头名称中含有非法字符或空格org.apache.coyote.http11.Http11Processor#line 311 Character set: org.apache.tomcat.util.http.parser.HttpParser#IS_TOKEN 400 Sample for illegal character Host: localhost Content-T(ype: application/xml X-SOA-OPERATION-NAME: getVersion\r\n\tsecond line\r\n\tthird line X-SOA-SERVICE-NAME: CoreShippingService Content-length: {requestBodyLength}400 Sample for blank Host: localhost Content-Type : application/xml X-SOA-OPERATION-NAME: getVersion\r\n\tsecond line\r\n\tthird line X-SOA-SERVICE-NAME: CoreShippingService Content-length: {requestBodyLength} 5. 存在多个Host请求头org.apache.coyote.http11.Http11Processor#line 609 400 Sample Host: localhost Host: localhost Content-Type: application/xml X-SOA-OPERATION-NAME: getVersion\r\n\tsecond line\r\n\tthird line X-SOA-SERVICE-NAME: CoreShippingService Content-length: {requestBodyLength} 6. 不存在Host请求头org.apache.coyote.http11.Http11Processor#line 612 400 Sample Host: localhost Content-Type: application/xml X-SOA-OPERATION-NAME: getVersion\r\n\tsecond line\r\n\tthird line X-SOA-SERVICE-NAME: CoreShippingService Content-length: {requestBodyLength} 7. 授权中的用户信息含有非法字符org.apache.coyote.http11.Http11Processor#line 660 Character set: org.apache.tomcat.util.http.parser.HttpParser#IS_USERINFO 400 Sample Host: localhost Content-Type: application/xml X-SOA-OPERATION-NAME: getVersion\r\n\tsecond line\r\n\tthird line X-SOA-SERVICE-NAME: CoreShippingService Content-length: {requestBodyLength} 8. URL中的Host与请求头中的Host不一致org.apache.coyote.http11.Http11Processor#line 686 400 Sample Host: localhost Content-Type: application/xml X-SOA-OPERATION-NAME: getVersion\r\n\tsecond line\r\n\tthird line X-SOA-SERVICE-NAME: CoreShippingService Content-length: {requestBodyLength}9. Start line中协议名称非法 org.apache.coyote.http11.Http11Processor#line 705 400 Sample Host: localhost Content-Type: application/xml X-SOA-OPERATION-NAME: getVersion\r\n\tsecond line\r\n\tthird line X-SOA-SERVICE-NAME: CoreShippingService Content-length: {requestBodyLength} 10. URI 中含有非法字符org.apache.coyote.http11.Http11Processor#line 713 Character set: org.apache.tomcat.util.http.parser.HttpParser#IS_ABSOLUTEPATH_RELAXED 400 Sample Host: localhost Content-Type: application/xml X-SOA-OPERATION-NAME: getVersion\r\n\tsecond line\r\n\tthird line X-SOA-SERVICE-NAME: CoreShippingService Content-length: {requestBodyLength} 11. 请求头中Content-Length值不为数字org.apache.coyote.http11.Http11Processor#line 739 400 Sample POST /ws/spf HTTP/1.1 Host: localhost Content-Type: application/xml X-SOA-OPERATION-NAME: getVersion\r\n\tsecond line\r\n\tthird line X-SOA-SERVICE-NAME: CoreShippingService Content-length: abc12. 请求头中含有多个Content-Length org.apache.coyote.http11.Http11Processor#line 741 400 Sample POST /ws/spf HTTP/1.1 Host: localhost Content-Type: application/xml X-SOA-OPERATION-NAME: getVersion\r\n\tsecond line\r\n\tthird line X-SOA-SERVICE-NAME: CoreShippingService Content-length: {requestBodyLength} Content-length: {requestBodyLength} |
CopyRight 2018-2019 实验室设备网 版权所有 |