03 Sep 2012

jetty处理 http response header中文字符,调试笔记

这段时间,我和几个同事在做另外一个美味书签,一个没有选辑,专注收藏的服务,和有选辑的美味书签并存。

大家讨论,觉得url应该是尽量清晰简单。比如张三用户登陆,它的url是/u/张三,之类的。能让高级用户直接输入url。url是可读的。

我们的程序用clojure开发。用ring,compojure, jetty。

我遇到了一个问题,在jetty返回给浏览器的http header中, 中文成了乱码。

场景如下:

  1. 张三到达我们网站,他在美味书签的用户名也是张三,输入的网址是landing page的 url: http://meiweisq.com/
  2. 程序发现,此用户已经登陆过,redirect到他的首页 /u/张三
  3. 浏览器看见的却是 /u/??

在第2和第3步之间出问题了。jetty在encode

{
     :status 302
     :headers {"Location" "/u/张三"}
     :body nil
     }

时出现乱码。尝试各种方法无果。

无奈之下换上我手工写的一个ring adapter, 发现也出现乱码,赶快修改了encode header相关代码, 从ASCII改为UTF8,问题解决。

但这只是一个临时的解决方法。

下班回家后,还在琢磨这件事, download了jetty的代码:

git clone git://github.com/eclipse/jetty.project.git

checkout 我们用的相应版本7.6.1.v20120215。

经过一番查找,调试,发现了问题所在, jetty在encode http response header时,用了hardcode的 ISO-8859-1

这段代码是用来encode http header的:

// ./jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java
// 322行到347行
  private Buffer convertValue(String value)
    {
        Buffer buffer = __cache.get(value);
        if (buffer!=null)
            return buffer;

        try
        {
            buffer = new ByteArrayBuffer(value,StringUtil.__ISO_8859_1);

            if (__cacheSize>0)
            {
                if (__cache.size()>__cacheSize)
                    __cache.clear();
                Buffer b=__cache.putIfAbsent(value,buffer);
                if (b!=null)
                    buffer=b;
            }

            return buffer;
        }
        catch (UnsupportedEncodingException e)
        {
            throw new RuntimeException(e);
        }
    }

StringUtil.__ISO_8859_1的定义

// ./jetty-util/src/main/java/org/eclipse/jetty/util/StringUtil.java

    public static final String __ISO_8859_1="ISO-8859-1";
    public final static String __UTF8="UTF-8";
    public final static String __UTF8Alt="UTF8";
    public final static String __UTF16="UTF-16";

解决办法

{
:status 302
:headers {"Location" (URLEncoder/encode "/u/张三")}
:body nil
}

后面想到可以用另外的方式绕过jetty编码http header的问题:

  • 返回一个网页,网页里面用js
location.href="/u/张三"
<meta http-equiv="refresh" content="0;URL='/u/张三'">
blog comments powered by Disqus