为什么像中文和丹麦语这样的非 ASCII 字符在 Tomcat 8 Url 重写中被破坏?

Why are non-ASCII charcters like chinese and danish getting mangled in Tomcat 8 Url Rewrite?

我正在将 URL 重写功能从 Apache mod_rewrite 迁移到 Tomcat 8 的 RewriteValve。有一些规则,例如

RewriteRule ^/abc/(.*)$ /xyz.do?param= [L]

重写的 URL 不适用于中文和其他此类非 ASCII 字符。检查重写日志,我发现 URL 重写工作正常。在访问日志中,非 ASCII 字符打印为问号字符。但是这些 URL 与 Apache 的 mod_rewrite.

一起工作得很好

实际URL是http://www.example.com/abc/在线测试

重写日志

Rewrote /abc/在线测试 as /xyz.do?param=在线测试 with rule pattern ^/abc/(.*)$

访问日志

/xyz.do?param=????

编辑

进一步调试我发现这种行为只适用于查询字符串。我正在使用 Tomcat 8.0.35.

rewrite.config 文件

RewriteRule ^/abc/(.*)$ /xyz? [L]

RewriteRule ^/test/(.*)/(. *)$ /test/? [L]

我添加了一个自定义记录阀

public class CustomValve extends ValveBase {

private static final Logger logger = Logger.getLogger(CustomValve.class.getName());

public void invoke(Request request, Response response) throws IOException, ServletException {
         HttpServletRequest httpServletRequest = request.getRequest();
         String contextPath = request.getRequestURI();
         logger.log(Level.SEVERE, "Context Path: "+contextPath);
         String queryString = request.getQueryString();
         if(queryString != null)
         {
                logger.log(Level.SEVERE, "QueryString: "+request.getQueryString());
         }
         else 
         {
                logger.log(Level.INFO, "QueryString: Null");
         }
         getNext().invoke(request, response);
   }
 }

此记录阀配置有重写阀

context.xml

<Context> 
     <Valve className="org.apache.catalina.valves.rewrite.RewriteValve"/>
     <Valve className="com.logging.valves.CustomValve"/>
</Context>

URL 访问过

http://localhost:8080/test/在线测试/在线测试

已记录自定义记录器

上下文路径:/test/%E5%9C%A8%E7%BA%BF%E6%B5%8B%E8%AF%95
QueryString: 在线测试

访问日志

/test/%E5%9C%A8%E7%BA%BF%E6%B5%8B%E8%AF%95????

请求 URI 中的非 ASCII 字符已编码,但查询字符串仍未编码。检查 Tomcat 的 RewriteValve 的实现,我发现请求 URI 已编码。

request.getCoyoteRequest().requestURI().setString(null);
CharChunk chunk = request.getCoyoteRequest().requestURI().getCharChunk();
chunk.recycle();
if (this.context) {
    chunk.append(contextPath);
}
//encoding of request URI
chunk.append(URLEncoder.DEFAULT.encode(urlString));
request.getCoyoteRequest().requestURI().toChars();

但是查询字符串没有这样的编码

if (queryString != null) {
        request.getCoyoteRequest().queryString().setString(null);
        chunk = request.getCoyoteRequest().queryString().getCharChunk();
        chunk.recycle();
        chunk.append(queryString);
        request.getCoyoteRequest().queryString().toChars();
}

有没有办法解决这个问题?

Bug 60013

似乎是 RewriteValve 实现中的错误。