java 将 Tomcat 5.5 配置为 UTF-8 编码所有 sendRedirect() 重定向?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/846409/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 14:01:38  来源:igfitidea点击:

Configuring Tomcat 5.5 to UTF-8 encode all sendRedirect() redirections?

javaweb-applicationsservletsutf-8url-encoding

提问by ubermensch

A requirement of the product that we are building is that its URL endpoints are semantically meaningful to users in their native language. This means that we need UTF-8 encoded URLs to support every alphabet under the sun.

我们正在构建的产品的一个要求是,它的 URL 端点对于使用他们母语的用户在语义上是有意义的。这意味着我们需要 UTF-8 编码的 URL 来支持阳光下的每个字母表。

We would also not like to have to provide installation configuration documentation for every application server and version that we support, so it would be nice if we could accomplish this in-code. This might not be possible, since by the time that the Servlet has received the request, its been encoded by the App server, etc.

我们也不想为我们支持的每个应用程序服务器和版本提供安装配置文档,所以如果我们能在代码中完成这个会很好。这可能是不可能的,因为在 Servlet 收到请求时,它已被应用服务器等编码。

I've gotten this working (for my first use case using ISO-Latin non-US ASCII characters) by reconstituting the request's path info with:

通过将请求的路径信息重构为以下内容,我已经开始工作(对于我使用 ISO-Latin 非美国 ASCII 字符的第一个用例):

String pathInfoEncoded = new String(httpServletRequest.getPathInfo().getBytes(), "UTF-8");

and then parsing that.

然后解析它。

However, this doesn't work after redirecting from a POST to a GET using sendRedirect(). The request's path comes in already escaped (so ? is encoded as %F6) and my method above doesn't work.

但是,这在使用 sendRedirect() 从 POST 重定向到 GET 后不起作用。请求的路径已经转义了(所以 ? 被编码为 %F6)并且我上面的方法不起作用。

So I guess my question is am I going about this all wrong? And if so, whats the antidote to my ignorance? :)

所以我想我的问题是我对这一切都做错了吗?如果是这样,我无知的解药是什么?:)

Update : found the solution. The problem is that the Servlet API has some weird behaviour with regards to URL encoding before sending the redirect. You have to URL-encode (escape the UTF-8 characters) BEFORE you call sendRedirect(). The encodeRedirectURL() method doesn't do it for you.

更新:找到解决方案。问题是 Servlet API 在发送重定向之前在 URL 编码方面有一些奇怪的行为。在调用 sendRedirect() 之前,您必须进行 URL 编码(转义 UTF-8 字符)。encodeRedirectURL() 方法不适合您。

This page discusses it: http://www.whirlycott.com/phil/2005/05/11/building-j2ee-web-applications-with-utf-8-support/

此页面讨论它:http: //www.whirlycott.com/phil/2005/05/11/building-j2ee-web-applications-with-utf-8-support/

回答by Stu Thompson

A couple things to investigate and experiment with:

需要调查和试验的几件事:

  • Have a look at your ./conf/server.xml file and ensure that the connector has the URIEncoding attribute set to "UTF-8".
  • 查看您的 ./conf/server.xml 文件并确保连接器的 URIEncoding 属性设置为“UTF-8”。

E.g.:

例如:

<Connector port="8080" 
           protocol="HTTP/1.1" 
           URIEncoding="UTF-8"/>
  • Use some sort of browser-based tool (E.g.: TamperDatafor FireFox) to see what your browser is sending to the server--it very well may be escaping it for you. If this is the case, you can use URL.decode()it on the server.
  • Instead of using Response.redirect(), manually set the headers and response code.
  • 使用某种基于浏览器的工具(例如:TamperDatafor FireFox)来查看您的浏览器正在向服务器发送什么——它很可能会为您转义它。如果是这种情况,您可以在服务器上使用URL.decode()它。
  • 手动设置标头和响应代码,而不是使用 Response.redirect()。

E.g.:

例如:

response.setHeader("Location", myUtf8unencodedUrl);
response.setStatus(response.SC_MOVED_TEMPORARILY);

No promises, but this is what I would try out if it were me. :)

没有承诺,但如果是我,这就是我会尝试的。:)

回答by ubermensch

found the solution. The problem is that the Servlet API has some weird behaviour with regards to URL encoding before sending the redirect. You have to URL-encode (escape the UTF-8 characters) BEFORE you call sendRedirect(). The encodeRedirectURL() method doesn't do it for you.

找到了解决方案。问题是 Servlet API 在发送重定向之前在 URL 编码方面有一些奇怪的行为。在调用 sendRedirect() 之前,您必须进行 URL 编码(转义 UTF-8 字符)。encodeRedirectURL() 方法不适合您。

This page discusses it: http://www.whirlycott.com/phil/2005/05/11/building-j2ee-web-applications-with-utf-8-support/

此页面讨论它:http: //www.whirlycott.com/phil/2005/05/11/building-j2ee-web-applications-with-utf-8-support/

回答by ubermensch

We have the same situation here, i.e. our product as well is required to show meaningful URLs to the user in potentially every language on earth. All our tools and techniques are supporting UTF-8, so no problem with that. Escaping the UTF-8 characters technically works, but IE (7, 8) shows the ugly looking escaped URLs whereas Firefox unescapes them and displays nice urls, i.e. '/fran?ais/Banane.html' will be displayed in IE as '/fran%C3%A7ais/Banane.html'. GET after POST / redirecting after form submits did not work at all, neither sending UTF-8 urls nor escaped UTF-8 urls. We also tried to use XML-style numeric entity coding without success.

我们在这里遇到了同样的情况,即我们的产品也需要以地球上可能的每种语言向用户显示有意义的 URL。我们所有的工具和技术都支持 UTF-8,所以没问题。转义 UTF-8 字符在技术上是可行的,但 IE (7, 8) 显示转义的 URL 看起来很丑,而 Firefox 对它们进行转义并显示漂亮的 URL,即“/fran?ais/Banane.html”将在 IE 中显示为“/ fran%C3%A7ais/Banane.html'。POST 后 GET / 表单提交后重定向根本不起作用,既不发送 UTF-8 网址,也不转义 UTF-8 网址。我们还尝试使用 XML 样式的数字实体编码,但没有成功。

However, we finally found a way to successfully redirect after a POST: encoding the UTF-8 string bytewise using ISO-8859-1. None of us really understands how this can work anyway (how can the browser know how to decode that, as the number of bytes per utf-8 character may vary and how does the browser know, it originally was utf-8?) , but it does.

然而,我们终于找到了一种在 POST 后成功重定向的方法:使用 ISO-8859-1 对 UTF-8 字符串进行字节编码。我们都没有真正理解这到底是如何工作的(浏览器如何知道如何解码,因为每个 utf-8 字符的字节数可能会有所不同,浏览器如何知道它最初是 utf-8?),但是确实如此。

Here's a simple servlet to try that out:

这是一个简单的 servlet 来尝试:


package springapp.web.servlet;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.io.IOUtils;

public class TestServlet extends HttpServlet {

 private static final long serialVersionUID = -1743198460341004958L;

 /* (non-Javadoc)
  * @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
  */
 @Override
 protected void doGet(HttpServletRequest req, HttpServletResponse resp)
   throws ServletException, IOException {

  String url = "??ffte.html"; 
  try {
         ServletContext context = req.getSession().getServletContext();
   // read utf8 encoded russian url
            if (context.getResource("/WEB-INF/ru_url.txt") != null){
             InputStream is = context.getResourceAsStream("/WEB-INF/ru_url.txt"); 
             if (is != null){
              url = IOUtils.toString(is, "UTF-8");
              System.out.println(String.format("Redirecting to [%s]", url));
             }
            }
        }
        catch (FileNotFoundException fNFEx) {
         fNFEx.printStackTrace();
        }
        catch (IOException ioEx) {
         ioEx.printStackTrace();
        }

        byte[] utfBytes = url.getBytes("UTF-8");
        String result = new String(utfBytes, "ISO-8859-1");
        resp.sendRedirect(result);

        // does not work:
        //resp.sendRedirect(url);
        //resp.sendRedirect(Utf8UrlEscaper.escapeUtf8(url));
        //resp.sendRedirect(Utf8UrlEscaper.escapeToNumericEntity(url));
 }
}

For the redirect target copy and paste any native language url e.g. from wikipedia in a utf-8 encoded (without BOM!) file and save that in the WEB-INF directory. In our example we took a russian url (http://ru.wikipedia.org/wiki/Заглавная_страница) and save that in a file named 'ru_url.txt'.

对于重定向目标,复制并粘贴任何本地语言网址,例如来自维基百科的 utf-8 编码(无 BOM!)文件,并将其保存在 WEB-INF 目录中。在我们的示例中,我们采用了一个俄语 url ( http://ru.wikipedia.org/wiki/Заглавная_страница) 并将其保存在名为“ru_url.txt”的文件中。

We created a simple SpringMVC application mapping any *.abc url to the test servlet. Now if you start the app and enter something like 'localhost:8080/springmvctest/a.abc' you should be redirected to the russian wikipedia site and the browser (IE and Firefox, Safari or else possibly not) should show a nice utf-8 encoded, native russion url.

我们创建了一个简单的 SpringMVC 应用程序,将任何 *.abc url 映射到测试 servlet。现在,如果您启动应用程序并输入诸如“localhost:8080/springmvctest/a.abc”之类的内容,您应该被重定向到俄罗斯维基百科站点,并且浏览器(IE 和 Firefox、Safari 或其他可能不是)应该显示一个不错的 utf- 8 编码的原生 russion 网址。