【问题标题】:Broken UTF-8 URI Encoding in JSPsJSP 中损坏的 UTF-8 URI 编码
【发布时间】:2012-07-15 08:15:48
【问题描述】:

我遇到了一个关于 URI 编码错误的奇怪问题,希望能提供任何帮助!

该项目使用 JSP、Servlet、Jquery、Tomcat 6。

JSP 中的字符集设置为 UTF-8,所有 Tomcat 连接器都使用 URIEncoding=UTF-8,我还使用了here 所述的字符编码过滤器。 另外,我在元标记中设置了 contentType,我的浏览器可以正确检测到它。

在使用 Jquery 的 Ajax 调用中,我根据我想用作 URL 参数的术语使用 encodeURIComponent(),然后使用 $.param() 序列化整个参数集。在被调用的 servlet 中,这些参数使用 Java.net.URLDecoder.decode(term, "UTF-8") 正确解码。

在某些地方,我从 JSP 中的参数映射生成 href 元素的 URL。每个参数值在 JSP 端使用 Java.net.URLEncoder.encode(value, "UTF-8") 进行编码,但随后以与之前相同的方式对其进行解码会导致特殊字符损坏。相反,我必须在 JSP 中将其编码为“ISO-8859-2”,然后在 servlet 中将其正确解码为“UTF-8”。

一个澄清的例子: 术语“überfall”是通过 Javascript (%C3%BCberfall) 进行 URIEncoded 并发送到 servlet 进行解码和处理,这很有效。将其传递回 JSP 后,我会将其编码为 UTF-8 并构建 URL,例如:

<a href="/myWebapp/servletPath?term=%C3%BCberfall">Click here</a>

但是,单击此链接会将参数作为“%C3%83%C2%BCberfall”发送到解码为“überfall”的 servlet。不进行编码时也会发生同样的情况。

当使用“ISO-8859-2”进行编码时,我得到:

<a href="/myWebapp/servletPath?term=%FCberfall">Click here</a>

单击此链接时,我可以在 Wireshark 中观察到 %C3%BCberfall 作为参数发送,该参数再次解码为“überfall”!

谁能告诉我我错过了什么?

编辑: 在 Firebug 中观察网络选项卡时,我意识到通过使用

$.param({term : encodeURIComponent(term)}); 

该术语被 UTF-8 编码两次,导致“%25C3%25BCberfall”,即百分号也是百分号编码的。类似地,如果我对参数映射中的每个值调用 encode(term, "UTF-8") 两次,它对我有用。

编码一次而不解码字符串会再次导致“überfall”。

【问题讨论】:

  • This is a thorough answer 为 UTF-8 设置 Java webapp。我保留它以供参考。但是,我认为您已经涵盖了所有内容,但还不知道如何解决您的问题,抱歉。
  • 如果您查看html的源代码,那么href是什么样的?
  • @Wolfram 谢谢,这是一个很好的总结。我认为我已经实现了那里列出的所有内容......
  • @jontro 我帖子中的 html sn-ps 来自 Firebug 中显示的页面源代码。
  • @KahPhi 你不应该解码 request.getParameter() 的结果。这应该已经由 servlet 过滤器完成了,这可能是原因吗?

标签: java jsp encoding utf-8 tomcat6


【解决方案1】:

Java 在内部使用什么编码?你是用

开始你的应用程序的吗?
-Dfile.encoding=utf-8

请说明“JSP 中的参数映射”的定义位置。它是来自一些持久性数据存储还是您的代码中以文字形式给出的字符串?

关于正在发生的事情的一些想法,这可能会有所帮助:

ü 是在读取 UTF-8 编码的 ü 时出现的结果,期望 ISO-8859-1,当每个字节都被自己解码时。 %C3%BCUTF-8 ü 的两个UTF-8 字节的URI 编码表示。我认为这是正在发生的事情:

%C3%BC错误地 解码为 → ü 被编码为 → %C3%83%C2%BC然后再次解码为 → ü 所以你最终得到überfall

所以我猜,您在解码 URI 编码字符串时使用了错误的编码。这可能与 Java/JVM 使用的内部编码有关:

By default, the JRE 7 installer installs a European languages version if it recognizes that the host operating system only supports European languages.

【讨论】:

  • 我没有明确设置这个参数,但是我在 bash 中检查了 Tomcat 进程,从 Eclipse 中启动它时显然设置正确。
  • 我会尝试在 eclipse.ini 中设置它,看看它是否会有所作为。由于 '%' 在 UTF-8 和 ISO 编码中都是 '%25',所以我在编辑中提到的双重编码符合您的假设,即在某处设置了 ISO 编码。参数映射也内置在这个 servlet 中,并保存为在 jsp 中读取的会话属性。 webapp 查询一个 Rest 服务并且使用 utf-8 参数没有问题,即在没有特殊编码的情况下发送和接收“überfall”作为术语。错误似乎发生在浏览器和tomcat之间。
【解决方案2】:

我想我现在肯定解决了这个问题。

根据 Jontro 的评论,我对所有 URL 参数值进行了一次编码,并删除了手动 servlet 端解码。

发送ü 应该看起来像Firebug 的网络选项卡中的%C3%BC,它在servlet 中给了我ü。 Java 使用 -Dfile.encoding 参数绝对设置为“UTF-8”内部编码。 我将问题追溯到这样的 request.getParameter() 方法。 request.getQueryString 没问题,但提取实际参数时失败:

request.getCharacterEncoding()) => UTF-8
request.getContentType() => null
request.getQueryString() => from=0&resultCount=10&sortAsc=true&searchType=quick&term=%C3%BC
request.getParameter("term") => ×
Charset.defaultCharset() => UTF-8
OutputStreamWriter.getEncoding() => UTF8
new String(request.getParameter("term").getBytes(), UTF-8) => ×
System.getProperty("file.encoding") => UTF-8

通过查看实现 request.getParameter() 的 Tomcat 和 Coyote 的来源,我发现了问题:来自连接器的 URIEncoding 始终为空,在这种情况下,它默认为 org.apache.coyote.Constants.DEFAULT_CHARACTER_ENCODING就像 Wolfram 所说的“ISO-8859-1”。

长话短说:我的错是在 Tomcat 的 conf 目录中编辑 server.xml,只有在服务器视图中创建新服务器时才会将其加载到 Eclipse 中!之后,必须编辑 Servers 项目中的单独 server.xml。这样做后,连接器设置已正确加载,一切正常。

感谢cmets!希望这对某人有所帮助...

【讨论】:

  • 我感觉 eclipse 在某处保留了一份副本,遇到了完全相同的问题。你刚刚结束了 6 小时的痛苦 :) 谢谢
猜你喜欢
  • 2010-11-23
  • 2019-07-19
  • 1970-01-01
  • 2014-12-16
  • 2013-02-02
  • 2014-09-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多