通过 PrimeFaces 输入组件检索的 Unicode 输入已损坏 [英] Unicode input retrieved via PrimeFaces input components become corrupted

查看:21
本文介绍了通过 PrimeFaces 输入组件检索的 Unicode 输入已损坏的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我还在使用 PrimeFaces v2.2.1 时,我可以使用 PrimeFaces 输入组件(例如

)输入 unicode 输入,例如中文:editor>,并在托管 bean 方法中以良好的形式检索输入.

When I was still using PrimeFaces v2.2.1, I was able to type unicode input such as Chinese with a PrimeFaces input component such as <p:inputText> and <p:editor>, and retrieve the input in good shape in managed bean method.

但是,在我升级到 PrimeFaces v3.1.1 后,所有这些字符都变成了 Mojibake 或问号.只有拉丁文输入没问题,是中文、阿拉伯文、希伯来文、西里尔文等字符出现格式错误.

However, after I upgraded to PrimeFaces v3.1.1, all those characters become Mojibake or question marks. Only Latin input comes fine, it are the Chinese, Arabic, Hebrew, Cyrillic, etc characters which become malformed.

这是怎么引起的,我该如何解决?

How is this caused and how can I solve it?

推荐答案

简介

通常情况下,JSF/Facelets 会在创建/恢复视图时默认将请求参数字符编码设置为 UTF-8.但是,如果在创建/恢复视图之前 请求了任何请求参数,那么设置正确的字符编码为时已晚.请求参数只会被解析一次.

Introduction

Normally, JSF/Facelets will set the request parameter character encoding to UTF-8 by default already when the view is created/restored. But if any request parameter is been requested before the view is been created/restored, then it's too late to set the proper character encoding. The request parameters will namely be parsed only once.

从 2.x 升级后在 PrimeFaces 3.x 中失败是由 PrimeFaces 的 PrimePartialViewContext 中的新 isAjaxRequest() 覆盖引起的,它检查请求参数:

That it failed in PrimeFaces 3.x after upgrading from 2.x is caused by the new isAjaxRequest() override in PrimeFaces' PrimePartialViewContext which checks a request parameter:

@Override
public boolean isAjaxRequest() {
    return getWrapped().isAjaxRequest()
            || FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().containsKey("javax.faces.partial.ajax");
}

默认情况下,isAjaxRequest()(Mojarra/MyFaces 之一,如上面的 PrimeFaces 代码通过 getWrapped() 获得的)检查请求头如下这不影响请求参数编码,因为在获取请求头时不会解析请求参数:

By default, the isAjaxRequest() (the one of Mojarra/MyFaces, as the above PrimeFaces code has obtained by getWrapped()) checks the request header as follows which does not affect the request parameter encoding as request parameters won't be parsed when a request header is obtained:

    if (ajaxRequest == null) {
        ajaxRequest = "partial/ajax".equals(ctx.
            getExternalContext().getRequestHeaderMap().get("Faces-Request"));
    }

但是,isAjaxRequest() 可以被任何阶段侦听器或系统事件侦听器或某些应用程序工厂在创建/恢复视图之前调用.因此,当您使用 PrimeFaces 3.x 时,请求参数将被解析之前设置正确的字符编码,因此使用服务器的默认编码,通常是 ISO-8859-1.这会搞砸一切.

However, the isAjaxRequest() may be called by any phase listener or system event listener or some application factory before the view is been created/restored. So, when you're using PrimeFaces 3.x, then the request parameters will be parsed before the proper character encoding is been set and hence use the server's default encoding which is usually ISO-8859-1. This will mess up everything.

有几种方法可以修复它:

There are several ways to fix it:

  1. 使用 servlet 过滤器,它设置 ServletRequest#setCharacterEncoding() 与UTF-8.通过 设置响应编码ServletResponse#setCharacterEncoding() 顺便说一下是不必要的,因为它不会受到这个问题的影响.

  1. Use a servlet filter which sets ServletRequest#setCharacterEncoding() with UTF-8. Setting the response encoding by ServletResponse#setCharacterEncoding() is by the way unnecessary as it won't be affected by this issue.

@WebFilter("/*")
public class CharacterEncodingFilter implements Filter {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");
        chain.doFilter(request, response);
    }

    // ...
}

你只需要考虑到HttpServletRequest#setCharacterEncoding()只设置POST请求参数的编码,而不是GET请求参数.对于 GET 请求参数,您仍然需要在服务器级别对其进行配置.

You only need to take into account that HttpServletRequest#setCharacterEncoding() only sets the encoding for POST request parameters, not for GET request parameters. For GET request parameters you'd still need to configure it at server level.

如果您碰巧使用 JSF 实用程序库 OmniFaces,那么已经提供了这样的过滤器,CharacterEncodingFilter.只需将其安装在 web.xml 中作为第一个过滤器条目:

If you happen to use JSF utility library OmniFaces, such a filter is already provided out the box, the CharacterEncodingFilter. Just install it as below in web.xml as first filter entry:

<filter>
    <filter-name>characterEncodingFilter</filter-name>
    <filter-class>org.omnifaces.filter.CharacterEncodingFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>characterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>


  • 重新配置服务器以使用 UTF-8 而不是 ISO-8859-1 作为默认编码.对于 Glassfish,只需将以下条目添加到 /WEB-INF/glassfish-web.xml文件:

    <parameter-encoding default-charset="UTF-8" />
    

    Tomcat 不支持.它在 条目中有 URIEncoding 属性,但这仅适用于 GET 请求,不适用于 POST 请求.

    Tomcat doesn't support it. It has the URIEncoding attribute in <Context> entry, but this applies to GET requests only, not to POST requests.

    将其作为错误报告给 PrimeFaces.是否有任何合法理由通过检查请求参数而不是像对标准 JSF 和例如 jQuery 所做的那样检查请求参数来检查 HTTP 请求是否为 ajax 请求?PrimeFaces 的 core.js JavaScript 就是这样做的.如果把它设置为XMLHttpRequest的请求头就更好了.

    Report it as a bug to PrimeFaces. Is there really any legitimate reason to check the HTTP request being an ajax request by checking a request parameter instead of a request header like as you would do for standard JSF and for example jQuery? The PrimeFaces' core.js JavaScript is doing that. It would be better if it has set it as a request header of XMLHttpRequest.

    <小时>

    不起作用的解决方案

    也许您在调查此问题时会在 Internet 某处偶然发现以下解决方案".这些解决方案在这种特定情况下永远不会起作用.解释如下.


    Solutions which do NOT work

    Perhaps you'll stumble upon below "solutions" somewhere on the Internet while investigating this problem. Those solutions do won't ever work in this specific case. Explanation follows.

    • 设置 XML 序言:

    • Setting XML prolog:

    <?xml version='1.0' encoding='UTF-8' ?>
    

    这只是告诉 XML 解析器在围绕它构建 XML 树之前使用 UTF-8 来解码 XML 源.在 JSF 查看构建时间期间,Facelts 实际使用的 XML 解析器是 SAX.这部分与 HTTP 请求/响应编码完全无关.

    This only tells the XML parser to use UTF-8 to decode the XML source before building the XML tree around it. The XML parser actually being used by Facelts is SAX during JSF view build time. This part has completely nothing to do with HTTP request/response encoding.

    设置 HTML 元标记:

    Setting HTML meta tag:

    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    

    当页面通过 http(s):// URI 通过 HTTP 提供时,HTML 元标记将被忽略.仅当页面被客户端保存为本地磁盘系统上的 HTML 文件,然后在浏览器中通过 file:// URI 重新打开时使用.

    The HTML meta tag is ignored when the page is served over HTTP via a http(s):// URI. It's only been used when the page is by the client saved as a HTML file on local disk system and then reopened by a file:// URI in browser.

    设置 HTML 表单接受字符集属性:

    Setting HTML form accept charset attribute:

    <h:form accept-charset="UTF-8">
    

    现代浏览器忽略了这一点.这仅在 Microsoft Internet Explorer 浏览器中有效.即使那样,它也做错了.永远不要使用它.所有真正的网络浏览器都将使用响应的 Content-Type 标头中指定的字符集属性.只要您不指定 accept-charset 属性,即使 MSIE 也会以正确的方式执行此操作.

    Modern browsers ignore this. This has only effect in Microsoft Internet Explorer browser. Even then it is doing it wrongly. Never use it. All real webbrowsers will instead use the charset attribute specified in the Content-Type header of the response. Even MSIE will do it the right way as long as you do not specify the accept-charset attribute.

    设置 JVM 参数:

    -Dfile.encoding=UTF-8
    

    这仅被 Oracle(!) JVM 用于读取和解析 Java 源文件.

    This is only used by the Oracle(!) JVM to read and parse the Java source files.

    这篇关于通过 PrimeFaces 输入组件检索的 Unicode 输入已损坏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆