1

我在获取某些网站的内容时遇到问题。当我尝试导航到重定向到另一个包含国际字符的 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 编码 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

谢谢帮助

4

1 回答 1

1

据我所知,当它的值是 UTF-8 编码时,Java 不会处理 Location 标头。

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’argent之间有一个字符(2019)的字符串。相反,它通过将这 3 个 UTF-8 字节中的每一个字节转换为字符 (E2 80 99) 来返回无效字符串。此时“loc”字符串是无用的。它不是有效的 Unicode 字符串。dargent

这是一个可能有帮助的解决方法:

  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 编码。

于 2012-11-12T18:21:09.170 回答