2012-11-12 14 views
1

我在獲取某些網站的內容時遇到問題。當我嘗試導航到重定向到包含國際字符的另一個url的url時,java通常會收到404錯誤。當我在瀏覽器中關注此URL時,我會得到有效的數據。Java重定向URL中的HttpUrlConnection國際字符

例如,我想轉到hXXp://shar.es/cISmv(不能發佈超過2個的有效鏈接)

瀏覽器重定向正確我hXXp://www.dandy-magazine。 com/la-griffe-de-la-tour-d%E2%80%99%。從wget我可以看到,最初的網站返回重定向301與現有的「位置:http://www.dandy-magazine.com/la-griffe-de-la-tour-d%E2%80%99argent

在java(whith重定向關閉)它返回重定向301與「Location: http://www.dandy-magazine.com/la-griffe-de-la-tour-dâargent」。使用url編碼ot看起來像這樣:「http://www.dandy-magazine.com/la-griffe-de-la-tour-d%C3%A2%C2%80%C2%99argent」。正如你所看到的,它是完全不同的網站。

示例代碼(基本版本1和版本2做同樣的事情):

// version 1 - let java handle redirects 
URL url = new URL("http://shar.es/cISmv"); 
HttpURLConnection con = (HttpURLConnection) url.openConnection(); 
con.setInstanceFollowRedirects(true); 
con.getResponseCode(); 
return con.getURL(); // returned url is not what it should be 

// version 2 - I want to handle redirects 
URL url = new URL("http://shar.es/cISmv"); 
HttpURLConnection con = (HttpURLConnection) url.openConnection(); 
con.setInstanceFollowRedirects(false); 
con.getResponseCode(); 
String loc = con.getHeaderField("Location"); 
// here is the problem, loc is not initialized with a correct url 
// returned String corresponds to url returned in version 1 

THX的幫助

+0

請小心使用正確的字符集編碼。您發佈的第一個鏈接可能使用iso 8859-1編碼,而第二個鏈接使用unicode編碼。 – Twilite

+0

嗨,thx評論。我稍微澄清了這個問題。基本上我的問題是,當我想從java和web瀏覽器訪問同一個站點時,我得到了不同的重定向結果。我懷疑問題可能出在字符編碼上,但我怎麼知道使用了什麼編碼?我該如何設置它? – Caldur

回答

1

據我所知,Java未能處理Location頭時,它的價值是UTF-8編碼的。

URL應該看起來像....../la-griffe-de-la-tour-d'argent。請注意,在前面的句子中,我使用ASCII單引號字符。然而而是採用了單引號字符的網站選擇使用Unicode字符

00002019 RIGHT SINGLE QUOTATION MARK 
Glyph: ’ 
UTF-8: E2 80 99 

一個Wireshark的跟蹤顯示返回Location頭具有這種性格UTF-8編碼。

00e0 65 70 2d 61 6c 69 76 65 0d 0a 4c 6f 63 61 74 69 ep-alive ..Locati 
00f0 6f 6e 3a 20 68 74 74 70 3a 2f 2f 77 77 77 2e 64 on: http ://www.d 
0100 61 6e 64 79 2d 6d 61 67 61 7a 69 6e 65 2e 63 6f andy-mag azine.co 
0110 6d 2f 6c 61 2d 67 72 69 66 66 65 2d 64 65 2d 6c m/la-gri ffe-de-l 
0120 61 2d 74 6f 75 72 2d 64 e2 80 99 61 72 67 65 6e a-tour-d ...argen 
0130 74 0d 0a 0d 0a 30 0d 0a 0d 0a      t....0.. ..  

我不知道這是否合法的HTTP。網上肯定有很多關於這個問題。不管它是否合法,HttpURLConnection類都不能很好地處理它。到

String loc = con.getHeaderField("Location"); 

調用應該返回的字符串http://www.dandy-magazine.com/la-griffe-de-la-tour-d’argentdargent之間,那裏有一個字符(2019)。相反,它會通過將這3個UTF-8字節中的每一個啞變換爲字符(E2 80 99)來返回一個無效字符串。在這一點上,「loc」字符串是無用的。這不是一個有效的Unicode字符串。

這裏是一個變通方法,可以幫助:

String loc = con.getHeaderField("Location"); 
    byte [] locbytes = new byte[loc.length()]; 
    for (int index = 0; index < locbytes.length; index++) 
    { 
    locbytes[index] = (byte) loc.charAt(index); 
    } 

    // use this loc instead 
    String loc2 = new String(locbytes, "UTF-8"); 

轉換僞造的字符串(其中每個字符有由Web服務器發送的字節的值)回一個字節數組。然後使用適當的字符集將字節數組轉換回字符串。現在使用loc2作爲你的URL打開一個新的連接。

有可能是一個更好的方法來做到這一點,但我沒有檢查源實現,以找出有辦法告訴HttpURLConnection類將頭值視爲UTF-8編碼。

+0

您的解決方案非常完美。非常感謝 – Pooya