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

Java 将Tomcat 5.5配置为UTF-8编码所有sendRedirect()重定向?,java,web-applications,servlets,utf-8,url-encoding,Java,Web Applications,Servlets,Utf 8,Url Encoding,我们正在构建的产品的一个要求是,它的URL端点对于使用母语的用户来说在语义上是有意义的。这意味着我们需要UTF-8编码的URL来支持太阳下的每个字母表 我们也不希望必须为我们支持的每个应用程序服务器和版本提供安装配置文档,所以如果我们能够在代码中完成这一点就好了。这可能是不可能的,因为在Servlet接收到请求时,它已经被应用服务器编码,等等 我通过使用以下内容重新构造请求的路径信息,实现了这一点(对于我的第一个使用ISO拉丁非美国ASCII字符的用例): String pathInfoEnco

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

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

我通过使用以下内容重新构造请求的路径信息,实现了这一点(对于我的第一个使用ISO拉丁非美国ASCII字符的用例):

String pathInfoEncoded = new String(httpServletRequest.getPathInfo().getBytes(), "UTF-8");
然后分析它

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

所以我想我的问题是,我是不是做错了?如果是这样,我无知的解药是什么

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


本页讨论它:

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

  • 查看您的./conf/server.xml文件,并确保连接器的URIEncoding属性设置为“UTF-8”
例如:


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

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


本页对此进行了讨论:

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

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

下面是一个简单的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));
 }
}
对于重定向目标,复制并粘贴任何本地语言url,例如来自wikipedia的utf-8编码(无BOM!)文件,并将其保存在WEB-INF目录中。在我们的示例中,我们使用了一个俄语url() 并将其保存在名为“ru_url.txt”的文件中

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

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

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));
 }
}