测试场景
使用Nginx代理SpringBoot应用,版本如下:
SpringBoot 2.1.3.RELEASE(内嵌tomcat9)
nginx-1.14.0
配置如下:
1 2 3 4 5 6 7 8 9 10 11 | upstream code_server_pool{ server 127.0.0.1:63049 weight=10; } server{ listen 80; server_name www.pbteach.com; #验证码 location ^~ /checkcode/ { proxy_pass http://code_server_pool/checkcode/; } ... |
使用postman测试报错
查看日志:
nginx日志:127.0.0.1 - - [08/May/2020:22:57:55 +0800] “POST /checkcode/getToken HTTP/1.1” 400 812 “-” “PostmanRuntime/7.1.1”
SpringBoot日志如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | java.lang.IllegalArgumentException: The character [_] is never valid in a domain name. at org.apache.tomcat.util.http.parser.HttpParser$DomainParseState.next(HttpParser.java:926) at org.apache.tomcat.util.http.parser.HttpParser.readHostDomainName(HttpParser.java:822) at org.apache.tomcat.util.http.parser.Host.parse(Host.java:71) at org.apache.tomcat.util.http.parser.Host.parse(Host.java:45) at org.apache.coyote.AbstractProcessor.parseHost(AbstractProcessor.java:288) at org.apache.coyote.http11.Http11Processor.prepareRequest(Http11Processor.java:809) at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:384) at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:834) at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1415) at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) 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) |
分析与解决
根据SpringBoot的报错得知,下划线字符“_”在域名中无效。
查看org.apache.tomcat.util.http.parser.HttpParser源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | public DomainParseState next(int c) { if (HttpParser.isAlpha(c)) { return ALPHA; } else if (HttpParser.isNumeric(c)) { return NUMERIC; } else if (c == '.') { if (allowsPeriod) { return PERIOD; } else { throw new IllegalArgumentException(sm.getString(errorMsg, Character.toString((char) c))); } } else if (c == ':') { if (allowsEnd) { return COLON; } else { throw new IllegalArgumentException(sm.getString(errorMsg, Character.toString((char) c))); } } else if (c == -1) { if (allowsEnd) { return END; } else { throw new IllegalArgumentException( sm.getString("http.invalidSegmentEndState", this.name())); } } else if (c == '-') { if (allowsHyphen) { return HYPHEN; } else { throw new IllegalArgumentException(sm.getString(errorMsg, Character.toString((char) c))); } } else { throw new IllegalArgumentException(sm.getString( "http.illegalCharacterDomain", Character.toString((char) c))); } |
早期使用SpringBoot低版本时没有此问题,升级SpringBoot后,内嵌的是Tomcat9版本,对域名的合法性进行校验中,包含下划线“_”则抛出异常。
修改nginx配置,将code_server_pool中的下划线去掉,修改如下:
1 2 3 4 5 6 7 8 9 10 11 | upstream codeserverpool{ server 127.0.0.1:63049 weight=10; } server{ listen 80; server_name www.pbteach.com; #验证码 location ^~ /checkcode/ { proxy_pass http://codeserverpool/checkcode/; } ... |
重启nginx解决此问题。