5

在这个问题上,我一直在用头撞墙。我读过类似的帖子和文章;大多数建议在 Tomcat 的 server.xml 文件中将 URIEncoding 设置为 UTF-8,但这在这里似乎没有什么区别。

我有一个 ReSTful Web 服务部署到托管在 Tomcat 7 上的测试环境。Tomcat 被配置为使用 Java 6,尽管 Java 7 也安装在机器上。对托管在那里的服务运行基本身份验证测试时,登录失败,当原始凭据包含 Unicode 字符时,我收到 HTTP 状态 401 的响应。当凭据仅包含 ASCII 时,基本身份验证工作正常。我也可以完全不使用基本身份验证登录 - 我的服务支持自定义登录标头和 RFC 2047。使用这种方法,凭据是否包含 Unicode 都没有关系,登录不是问题。

具体来说,“问题”似乎是用户名被 UTF-8 编码两次。我的记录器(单独的问题)中有一个错误,其中日志文件是 ANSI 编码的。当您将日志文件转换为 UTF-8 时,字符将正确显示。但是在这种情况下,有问题的用户名比它应该的长得多,当文件转换为 UTF-8 时,它看起来就像它最初应该有的一样(在转换之前)。例如:

  • BAD (BASIC AUTH): SampleUser-¢𣎴eÌ‚é¾± -> SampleUser-¢𣎴eÌ‚é¾±</li>
  • 好的(RFC 2047):SampleUser-¢𣎴eÌ‚é¾± -> SampleUser-¢ê龱</li>

这里真正的问题是我有自己的 Tomcat 7 (Java 6) 实例在本地运行,但我无法针对它重现问题。我比较了两个 Tomcat 的 conf 目录,它们看起来是一样的。我无法弄清楚为什么基本身份验证在一种环境中工作而不是在另一种环境中工作。我正在从我的机器上运行测试,所以这不可能是由于我测试它的方式(JUnit/JSystem)的差异。

这是我所知道的:

  • 就特权而言,我们谈论的用户类型无关紧要。用户名中的 Unicode 是有问题的因素。
  • 请求是通过 XML 还是 JSON 发送并不重要。我的服务支持这两种类型的序列化。
  • 接受字符集和内容类型(如果适用)在请求中都设置为 UTF-8。
  • Java 系统属性在两种环境中是相同的。

以下文章对我来说非常有趣,因为它们提出了将 RFC 2047 和基本身份验证结合在一起的可能性。我不认为这是必要的,因为基本的身份验证字符串本身只包含 ASCII(因为它是 base-64 编码的)。即使是这样,为什么在一台 Tomcat 服务器而不是另一台服务器上需要这样的东西?我觉得追求这种组合方法并没有解决根本问题,这才是真正让我发疯的原因!

提前感谢您提供有关尝试或仔细检查的建议。测试环境对我来说有点局限——我只能在下班时间“玩”,所以如果我没有及时回复,我提前道歉。

4

1 回答 1

4

从您提供的数据来看,实际上似乎 UTF-8 数据正在转换为 ASCII 编码,而不是双重 UTF-8 编码。

就实际问题而言,不幸的是,基本身份验证没有提供任何方式来传输未解码的用户名和密码的字符集。因此,您的主要选择是假设并手动指定字符集,使用环境中的默认字符集,或确定提供字符集的自定义方式(例如另一个标题)。每种选项都取决于您对环境和通信的客户端/服务器端的控制程度,以及您是否希望所有调用都使用相同的字符集。

基于一台服务器行为正确而另一台服务器行为不正确,我假设解码当前使用环境中的默认字符集。您是正确的,编码字符串将仅包含 ASCII(因此您可能没有看到传输编码值的问题),因此数据可能在解码过程中(或之后)丢失。根据您选择的库,它可能会生成字节数组或字符串,因此请确保在从字节数组创建字符串时检查您是否提供了字符集(例如 new String(decodedData, someCharset))或看看是否有办法将它提供给库(如果它产生一个字符串)。

于 2013-01-09T04:33:50.247 回答