最近做了一个服务,对外提供http接口,采用nginx反代,使用域名访问
但是为了容灾,客户端需要指定ip访问该服务,如果该ip坏掉,客户端就切换到另个一ip(靠dns解析太慢)
nginx上只配置了域名的分发,没有配置ip分发
于是在http请求上做了点处理,url配置ip,同时配置http头部的Host参数为该域名,
HttpURLConnection 有setRequestProperty(key,value)方法来设置http头部
通过ip访问,设置Host头部来让nginx识别,然后分发到相应的处理程序
代码如下
HttpURLConnection urlConn = null; String url = "http://192.168.1.120/login?platform=xxx&type=account"; URL destURL = new URL(url); urlConn = (HttpURLConnection) destURL.openConnection(); urlConn.setConnectTimeout(10000); urlConn.setReadTimeout(10000); urlConn.setRequestProperty("Host", "auth.xxx.com");
这里我们要访问192.168.1.120这个服务器的一个login服务,配置的域名是 auth.xxx.com
嗯,本地测试ok,就发布到服务器上了。
但是神奇的事情出现了,我们有5台服务器,其中2台可以,另外3台死活不行,总报错说404错误
404说明客户端请求路径不存在,推测估计是Host没有生效。
对比可以和不可以的两种服务器的环境,可以的jdk是 6U18,不可以的是6U24
于是怀疑jdk升级的问题,在网上搜了搜,找了HttpURLConnection的sun的源代码
http://javasourcecode.org/html/open-source/jdk/jdk-6u23/sun/net/www/protocol/http/HttpURLConnection.java.html
发现里面 有一个 allowRestrictedHeaders 这个参数,原来api在设计的时候,可能为了安全,限制了程序能够使用的Http Header
如,下面的都是限制的
private static final String[] restrictedHeaders = { /* Restricted by XMLHttpRequest2 */ //"Accept-Charset", //"Accept-Encoding", "Access-Control-Request-Headers", "Access-Control-Request-Method", "Connection", /* close is allowed */ "Content-Length", //"Cookie", //"Cookie2", "Content-Transfer-Encoding", //"Date", "Expect", "Host", "Keep-Alive", "Origin", // "Referer", // "TE", "Trailer", "Transfer-Encoding", "Upgrade", //"User-Agent", "Via" }; allowRestrictedHeaders = ((Boolean)java.security.AccessController.doPrivileged( new sun.security.action.GetBooleanAction( "sun.net.http.allowRestrictedHeaders"))).booleanValue();
里面就有我们要设置的Host,找到原因,就好解决了,只要告诉程序,允许能使用这些限制的头部即可
System.setProperty("sun.net.http.allowRestrictedHeaders", "true");
就ok了,搞定,收工。
【总结】
1.遇到同一份代码有的服务器可以,有的服务器不行的话,多半是环境问题,常见的环境问题有:
语言环境,字符集编码(如UTF-8/GB2312,虚拟机版本,环境变量路径等
2.没有找到6U18的代码,所以没有去找到底是哪个版本开始做了修改了。