java.lang.IllegalArgumentException: 在方法名中发现无效字符(CR或LF)

20

我有一个运行在Tomcat8上的Spring MVC应用程序。每隔一两天,我的日志文件中就会出现一个异常。

15-Jun-2016 10:43:39.832 INFO [http-nio-8080-exec-50] 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.
 java.lang.IllegalArgumentException: Invalid character (CR or LF) found in method name
    at org.apache.coyote.http11.AbstractNioInputBuffer.parseRequestLine(AbstractNioInputBuffer.java:228)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1009)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:672)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1502)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1458)
    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)

有人知道这可能是什么吗?


1
看起来传入的HTTP请求头是格式不正确的。正如错误消息所告诉您的那样,请求头中包含了HTTP方法名称中禁止使用的字符(行尾),因此请求解析器会抛出异常。所以这不是你代码中的问题。你可以忽略它或者要求发送方检查请求的有效性。 - Vladimir Vagaytsev
@Vladimir Vagaytsev - 请求来自Web,我们使用nginx设置了LB。在服务器上,它会抛出上述错误并显示Bad Gateway。scalescale.com/tips/nginx/502-bad-gateway-error-using-nginx没有帮助 :( - Narendra N
我相信,这个异常更多与SSL设置有关,因为相同的(或几乎相似的)war文件在我们使用http访问的stage机器上可以正常工作,而我们遇到问题的是测试生产环境,该环境使用https。我们需要检查nginx配置。如果你找到了解决方法,请告诉我 :) - Narendra N
嗨,VadOs,你的Tomcat是否在云机器上运行?如果是,请参考以下链接:(http://cyber4.org/three-legged-pig/captain-were-being-scanned-by-an-alien-ship/)和(https://confluence.atlassian.com/confkb/confluence-log-has-java-lang-illegalargumentexception-invalid-character-cr-or-lf-found-in-method-name-827127067.html)。 - Ramesh Subramanian
你们,有取得任何进展吗? - xenteros
6个回答

41

这个错误是由于格式错误的HTTP请求造成的。 在大多数情况下,此消息是误导性的,因为当你试图通过https访问不安全的页面时会发生此错误。 Tomcat不知道传入的请求是加密的,并试图将此请求解释为普通的、不安全的http请求。

以下是日志中可能显示的内容:

标准、正确的HTTP请求(http://localhost:8080

Received [GET /index.html HTTP/1.1
Host: localhost:8080
Connection: keep-alive
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.76 Mobile Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Encoding: gzip, deflate, sdch
Accept-Language: pl,en-US;q=0.8,en;q=0.6
Cookie: Idea-xxxxx; JSESSIONID=3dxxxxx

] 

HTTPS请求 (https://localhost:8080)

Received [¹µHÄ;ß!P@<¿
                                                                                                                                #|vFBb-Ëiø/5
jÿ

                   hhttp/1.1uP
                               
] 

如您所见,在第二个请求中,存在未知字符而非正确的HTTP方法名称(例如GET)

因此,如果您的服务器没有SSL配置,并且错误发生“一两天一次”,那么可能有人正在尝试通过https访问您的网站(很可能是某种机器人)

最终,某人试图发送非安全但格式不正确的纯HTTP请求(通过他自己的应用程序-机器人或其他自定义客户端)。


3
这个错误会导致Tomcat停止工作吗?我经常遇到这个异常,我的Tomcat在规律的时间间隔内停止工作。 - KJEjava48

3

关于使用springboot时的问题解决方法。 我之前使用的是HTTPS链接,但我的本地服务器并没有使用SSL,所以我更改了链接为HTTP,这样就解决了问题。


1

重新检查发送的请求。 如果终端点未启用https,则使用http传递请求。


1
我也遇到了HTTP POST请求相同的问题——问题是“JSON数据不正确”。在类中,我有一个枚举属性,我在对象中传递时写错了(拼写错误)。因此我得到了这个异常。

1
我遇到了同样的错误,它可能与您的Tomcat配置完全无关。找到错误让我疯狂。我正在为六个域名提供多个应用程序,其中只有一个域名产生了502代理错误。然后在Tomcat的日志catalina.out中发现“无效字符”消息:
Apr 18, 2018 10:31:06 AM org.apache.coyote.http11.AbstractHttp11Processor process
INFO: Error parsing HTTP request header
 Note: further occurrences of HTTP header parsing errors will be logged at DEBUG level.
java.lang.IllegalArgumentException: Invalid character (CR or LF) found in method name
        at org.apache.coyote.http11.InternalAprInputBuffer.parseRequestLine(InternalAprInputBuffer.java:177)
        at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:992)
        at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:625)
        at org.apache.tomcat.util.net.AprEndpoint$SocketWithOptionsProcessor.run(AprEndpoint.java:2454)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
        at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
        at java.lang.Thread.run(Thread.java:748)

在我的情况下,我正在使用代理从Apache httpd向Tomcat应用程序发送请求。代理指令在httpd的虚拟主机中使用,通常配置在/etc/httpd/conf.d/virtualhosts.conf中。代理首先将收到的端口80上的任何未加密的http请求重定向到端口443。
<VirtualHost *:80>
  ServerName www.domain1.com
  ServerAlias domain1.com *.domain1.com
  Redirect permanent / https://domain1.com/
</VirtualHost>

重定向请求会被视为一般的加密 https 请求进行处理。
错误的配置。不要复制这个!
  <VirtualHost *:443>
      ServerName www.domain1.com
      ServerAlias domain1.com *.domain1.com
      ProxyRequests off
      ProxyPreserveHost on
      CustomLog "/etc/httpd/logs/domain1ssl.log" "%h %l %u %t \"%r\" %>s %b"
      ErrorLog "/etc/httpd/logs/domain1ssl_error.log"
      SSLEngine on
      SSLProxyEngine on
      SSLCertificateFile /etc/pki/tls/certs/domain1.com.crt
      SSLCertificateKeyFile /etc/pki/tls/private/domain1.key
      SSLCertificateChainFile /etc/pki/tls/certs/ca-bundle-domain1.crt
      ProxyPass / https://domain1.com:8081/
      ProxyPassReverse / https://domain1.com:8081/
    </VirtualHost>

请注意这两行:
ProxyPass / https://domain1.com:8081/
  ProxyPassReverse / https://domain1.com:8081/

这些指令告诉Apache将请求作为加密请求发送到监听8081端口的进程。这是我的笔误。协议应该是http。Tomcat没有处理加密,而是由httpd处理加密。因此,Tomcat在非加密连接器上接收到加密请求,导致Maciej Marczuk(https://stackoverflow.com/users/1545775/maciej-marczuk)在其答案中详细解释的“无效字符”错误。非常感谢您帮我找到笔误。
代理指令应该是:
ProxyPass / http://domain1.com:8081/
  ProxyPassReverse / http://domain1.com:8081/

希望这能帮助到某个人。祝好。

0

这个错误可能是由于端口设置不正确导致的。

实际上,如果您想要使用HTTPS协议,需要注意默认的Tomcat端口是8443: https://localhost:8443

当您更改了连接器和密钥库,但仍然使用8080而不是8443时,就会出现这种情况。


1
这是很好的事实信息,但它没有以回答手头问题的方式编写。请删除此答案,并将其作为评论添加到最合适的答案中。 - Edwin Buck
1
我不同意。我发表这个评论是因为我由于错误的端口也遇到了完全相同的错误。 - hadf
没问题,但请重新回答并在某种程度上包含问题。您的回答也可以是“请注意,如果您想通过HTTP接受抛出,请使用默认Tomcat端口8080”,它将包含相同的信息:有关默认端口的信息。如果不将这些信息与他的问题相关联,那么我认为这个回答就不是真正回答了这个问题。事实是正确的,但说FTP的默认端口为21也是正确的。除非您展示事实和问题之间的关系,否则您不是在回答问题,而是只在说事实。 - Edwin Buck

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接