我在获取某些网站的内容时遇到问题。当我尝试导航到重定向到另一个包含国际字符的url的url时,java通常会收到错误404.当我在浏览器中关注此url时,我会获得有效数据。
例如,我想导航到hXXp://shar.es/cISmv(不能发布2个以上的有效链接)
浏览器将我正确地重定向到hXXp://www.dandy-magazine.com/la-griffe-de-la-tour-d%E2%80%99argent。从wget我可以看到,最初网站返回重定向301与现有的“位置:http://www.dandy-magazine.com/la-griffe-de-la-tour-d%E2%80%99argent”
在java(关闭重定向)中,它返回带有“Location: http://www.dandy-magazine.com/la-griffe-de-la-tour-dâargent
”的重定向301。使用url编码看起来像这样:“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
寻求帮助
答案 0 :(得分:1)
据我所知,当Java的值为UTF-8编码时,Java不会处理它。
网址应该看起来像...... / 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’argent
,其中d
和argent
之间只有一个字符(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");
将伪造的字符串(其中每个char具有Web服务器发送的字节的值)转换回字节数组。然后使用正确的字符集将字节数组转换回字符串。现在使用loc2作为您的URL打开一个新连接。
可能有更好的方法可以做到这一点,但我没有检查源实现,以确定有一种方法可以告诉HttpURLConnection类将标头值视为UTF-8编码。