1. 程式人生 > >HttpURLConnection 設定Host 頭部無效

HttpURLConnection 設定Host 頭部無效

最近做了一個服務,對外提供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的原始碼

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的程式碼,所以沒有去找到底是哪個版本開始做了修改了。