今天在调试代码的时候,发现一个get请求通过域名调用一直返回400 bad request的报错,但通过ip:端口号的形式就不会。经过仔细排查,发现服务端有如下的日志:
[org.apache.coyote.http11.Http11Processor] [DirectJDKLog.java:182] - The host [api_server] is not valid
Note: further occurrences of request parsing errors will be logged at DEBUG level.
java.lang.IllegalArgumentException: The character [_] is never valid in a domain name.
at org.apache.tomcat.util.http.parser.HttpParser$DomainParseState.next(HttpParser.java:983)
at org.apache.tomcat.util.http.parser.HttpParser.readHostDomainName(HttpParser.java:879)
at org.apache.tomcat.util.http.parser.Host.parse(Host.java:66)
at org.apache.tomcat.util.http.parser.Host.parse(Host.java:40)
at org.apache.coyote.AbstractProcessor.parseHost(AbstractProcessor.java:293)
at org.apache.coyote.http11.Http11Processor.prepareRequest(Http11Processor.java:1201)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:775)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:808)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1498)
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)
这段报错日志意思是在请求的header头中,有一个header: host=api_server 是不合法的,具体说下划线不是一个合法的域名字符。
在解决问题之前,有几个问题先要弄明白。首先,这个header中的host是从何而来?使用域名请求的原始header中并没有设置host的header,并且通过ip:端口号的形式就没有问题,那么很可能这个header是我们反向代理也就是nginx(当然具体看你用的是什么反代)带过来的。那为什么nginx会带这么一个header到后端呢?即使带的话也应该是原始的域名才对。直接看nginx关于这个域名的配置,会发现api_server是我们upstream的名称,也就是说nginx没有将原始的host带过来,取而代之的是upstream的名称。那查询文档就知道在server中设置 **proxy_set_header Host $host;**就可以将原始的host传递过来了。
错误是得到了解决,但假如说本来的域名就带的有_下划线呢?还是会报这个错。所以有必要了解下域名的命名规则。根据维基百科 en.wikipedia.org/wiki/Hostna… 关于hostname的限制中,只允许ASCII字符中a-z,数据0-9和中划线,且中划线不能作为开头和结尾。那么在各个域名解析运营商那配置域名的时候也要注意这个问题。
同时最开始的报错信息是tomcat8中的强限制,在tomcat7版本中是没有这个限制的,至于其他的框架还未做个详细的测试。