【问题标题】:Is there a way to use UTF-8 with app engine?有没有办法在应用引擎中使用 UTF-8?
【发布时间】:2012-08-08 02:46:44
【问题描述】:

我正在寻找有关应用引擎如何处理字符编码的一些解释。我正在开发一个客户端-服务器应用程序,其中服务器位于应用引擎上。

这是一个从头开始构建的新应用程序,因此我们在所有地方都使用 UTF-8。客户端通过 POST,x-www-form-urlencoded 向服务器发送一些字符串。我收到它们并回显它们。当客户取回它时,它是 ISO-8859-1!我在 POST 到 blobstore 时也看到了这种行为,参数以 UTF-8、multipart/form-data 编码发送。

为了记录,我在 Wireshark 中看到了这一点。所以我 100% 确定我发送 UTF-8 并接收 ISO-8859-1。另外,我没有看到 mojibake:ISO-8859-1 编码的字符串非常好。这也不是误解 Content-Type 的问题。这不是客户端。一路走来正确识别我正在发送 UTF-8 参数,但由于某种原因正在将它们转换为 ISO-8859-1。

我相信 ISO-8859-1 是 GAE servlet 的默认字符编码。我的问题是,有没有办法告诉 GAE 不要转换为 ISO-8859-1,而是在任何地方使用 UTF-8?

假设 servlet 做了这样的事情:

public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
    resp.setContentType("application/json");
    String name = req.getParameter("name");
    String json = "{\"name\":\"" + name + "\"}";
    resp.getOutputStream().print(json);
}

我尝试将响应和请求的字符编码设置为“UTF-8”,但这并没有改变任何内容。

提前致谢,

【问题讨论】:

  • 我不了解 GAE,但您的 API 看起来像 J2EE Servlets。那里 ISO-8859-1 确实是默认值。使用resp.setCharacterEncoding() 更改编码或直接打印二进制文件。
  • GAE 使用相同的 API。我已经尝试在响应中设置字符编码,它不起作用。 :( 不过谢谢。
  • 我根本没有使用过 appengine,但是对于所有 appserver,我必须实现一个过滤器来强制编码为 UTF-8(因为 Zeiss 提到的“问题”......愚蠢的 servlet规格)。如果您不想重新发明轮子,可以从tomcat 复制粘贴过滤器。
  • @Augusto:不,我没有尝试过。我看到的链接使用 Spring,我没有使用 Spring。您的链接未在此处加载。我在其他地方找到了该代码,我会试一试并回复您,谢谢。

标签: java google-app-engine servlets character-encoding


【解决方案1】:

这不是 GAE 特有的,但如果您觉得它有用:我制作了自己的过滤器:

在 web.xml 中

<filter>
    <filter-name>charsetencoding</filter-name>
    <filter-class>mypackage.CharsetEncodingFilter</filter-class>
</filter>
    ...
<filter-mapping>
   <filter-name>charsetencoding</filter-name>
   <url-pattern>/*</url-pattern> 
</filter-mapping>

(将过滤器映射片段完全放在过滤器映射的开头,并检查您的 url-pattern。

还有

public class CharsetEncodingFilter implements Filter {

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse res = (HttpServletResponse) response;
        req.setCharacterEncoding("UTF-8");
        chain.doFilter(req, res);
        res.setCharacterEncoding("UTF-8");
    }

    public void destroy() { }

    public void init(FilterConfig filterConfig) throws ServletException { }
}

【讨论】:

  • 不。 :-(我也尝试使用Augusto的链接并将web.xml中的字符集配置为您发布的链接,但它仍然没有成功。我猜GAE不尊重这些过滤器?我仍然得到从 echo servlet 返回 ISO-8859-1。
  • 根据developers.google.com/appengine/docs/java/config/webxml GAE 确实支持过滤器。但是,过滤器所做的只是设置请求和响应字符编码。我已经在单个 servlet 中尝试过,但没有运气,所以我想这在 GAE 中是行不通的。
  • 即使在开发服务器中我也无法让它工作。我认为它使用 Jetty 来处理请求。
【解决方案2】:

我看到你应该做两件事。

1) 在您的 appengine-web.xml 中将系统属性(如果您正在使用)设置为 utf8

<system-properties>
    <property name="java.util.logging.config.file" value="WEB-INF/logging.properties" />
    <property name="file.encoding" value="UTF-8" />
    <property name="DEFAULT_ENCODING" value="UTF-8" />
</system-properties>

好的,以上是我所拥有的,但文档建议如下:

<env-variables>
    <env-var name="DEFAULT_ENCODING" value="UTF-8" />
</env-variables>

https://developers.google.com/appengine/docs/java/config/appconfig

2) 在设置内容类型时指定编码,否则将恢复为默认值

内容类型可能包括使用的字符编码类型,例如 例如,文本/html;字符集=ISO-8859-4。

我会试试的

resp.setContentType("application/json; charset=UTF-8");

您也可以尝试使用可以直接设置内容类型的编写器。

http://docs.oracle.com/javaee/1.3/api/javax/servlet/ServletResponse.html#getWriter%28%29
http://docs.oracle.com/javaee/1.3/api/javax/servlet/ServletResponse.html#setContentType(java.lang.String)

对于它的价值,我需要 utf8 用于日语内容,我没有问题。无论如何,我没有使用过滤器或 setContentType。我正在使用 gwt 和上面的 #1 并且它有效。

【讨论】:

  • 不,这也不起作用。 :-( 我禁用了过滤器,按照您的建议设置系统属性(使用 env-variables 不起作用,开发服务器拒绝运行)。然后我使用了 content-type "application/json; charset=utf-8 "(我认为是正确的),但它不起作用。我还复制并粘贴了您的内容类型行(我认为这是不正确的),同样的事情。
  • "resp.setContentType" 对我有用。
【解决方案3】:

找到了解决方法。我就是这样做的:

  • 使用“application/json; charset=UTF-8”作为内容类型。或者,将响应字符集设置为“UTF-8”(两者都可以正常工作,无需同时执行)。

  • Base64 编码非 ASCII 安全且以 UTF-8 形式出现的输入字符串。否则,当它们到达 servlet 时,它们显然会被转换为 ISO-8859-1。

  • 使用 resp.getWriter() 代替 resp.getOutputStream() 来打印 JSON 响应。

在满足所有这些条件后,我终于能够将 UTF-8 输出回客户端。

【讨论】:

    【解决方案4】:

    解决方法(安全)

    这些答案都不适合我,所以我编写了这个类来将 UTF-Strings 编码为 ASCII-Strings(用它们的表号替换所有不在 ASCII 表中的字符,前面和后面都有一个标记),使用AsciiEncoder.encode(yourString)

    然后可以使用AsciiEncoder.decode(yourAsciiEncodedString) 将字符串解码回UTF

    package <your_package>;
    
    import java.util.ArrayList;
    
    /**
     * Created by Micha F. aka Peracutor.
     * 04.06.2017
     */
    
    public class AsciiEncoder {
    
        public static final char MARK = '%'; //use whatever ASCII-char you like (should be occurring not often in regular text)
    
        public static String encode(String s) {
            StringBuilder result = new StringBuilder(s.length() + 4 * 10); //buffer for 10 special characters (4 additional chars for every special char that gets replaced)
            for (char c : s.toCharArray()) {
                if ((int) c > 127 || c == MARK) {
                    result.append(MARK).append((int) c).append(MARK);
                } else {
                    result.append(c);
                }
            }
            return result.toString();
        }
    
        public static String decode(String s) {
            int lastMark = -1;
            ArrayList<Character> chars = new ArrayList<>();
            try {
                //noinspection InfiniteLoopStatement
                while (true) {
                    String charString = s.substring(lastMark = s.indexOf(MARK, lastMark + 1) + 1, lastMark = s.indexOf(MARK, lastMark));
                    char c = (char) Integer.parseInt(charString);
                    chars.add(c);
                }
            } catch (IndexOutOfBoundsException | NumberFormatException ignored) {}
    
            for (char c : chars) {
                s = s.replace("" + MARK + ((int) c) + MARK, String.valueOf(c));
            }
            return s;
        }
    }
    

    希望这对某人有所帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-01-07
      • 1970-01-01
      • 2012-07-03
      • 1970-01-01
      • 2015-05-01
      • 1970-01-01
      • 2013-02-10
      • 2011-06-28
      相关资源
      最近更新 更多