最近做了一個服務,對外提供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的代碼,所以沒有去找到底是哪個版本開始做了修改了。