UTF-8 encoding of GET parameters in JSF

2019-06-16 05:59发布

问题:

I have a search form in JSF that is implemented using a RichFaces 4 autocomplete component and the following JSF 2 page and Java bean. I use Tomcat 6 & 7 to run the application.

...
<h:commandButton value="#{msg.search}" styleClass="search-btn" action="#{autoCompletBean.doSearch}" />
...

In the AutoCompleteBean

public String doSearch() {

   //some logic here
   return "/path/to/page/with/multiple_results?query=" + searchQuery + "&amp;faces-redirect=true";

}

This works well as long as everything withing the "searchQuery" String is in Latin-1, it does not work if is outside of Latin-1.

For instance a search for "bodø" will be automatically encoded as "bod%F8". However a search for "Kra Ðong" will not work since it is unable to encode "Ð".

I have now tried several different approaches to solve this, but none of them works.

  • I have tried encoding the searchQuery my self using URLEncode, but this only leads to double encoding since % is encoded as %25.
  • I have tried using java.net.URI to get the encoding, but gives the same result as URLEncode.
  • I have tried turning on UTF-8 in Tomcat using URIEncoding="UTF-8" in the Connector but this only worsens that problem since then non-ascii characters does not work at all.

So to my questions:

  1. Can I change the way JSF 2 encodes the GET parameters?
  2. If I cannot change the way JSF 2 encodes the GET parameters, can I turn of the encoding and do it manually?
  3. Am I doing something where strange here? This seems like something that should be supported out-of-the-box, but I cannot find any others with the same problem.

回答1:

I think you've hit a corner case bug in JSF. The query string is URL-encoded by ExternalContext#encodeRedirectURL() which uses the response character encoding as obtained by ExternalContext#getResponseCharacterEncoding(). However, while JSF by default uses UTF-8 as response character encoding, this is only been set if the view is actually to be rendered, not when the response is to be redirected, so the response character encoding still returns the platform default of ISO-8859-1 which causes your characters to be URL-encoded using this wrong encoding.

I've reported this as issue 2440. In the meanwhile your best bet is to explicitly set the response character encoding yourself beforehand.

FacesContext.getCurrentInstance().getExternalContext().setResponseCharacterEncoding("UTF-8");

Note that this still requires that the container itself uses the same character encoding to decode the request URL, so you certainly need to set URIEncoding="UTF-8" in Tomcat's configuration. This won't mess up the characters anymore as they will be really UTF-8 now.



回答2:

The only character encoding accepted for HTTP URLs and headers is US-ASCII, you need to URL encode these characters to send them back to the application. Simplest way to do this in java would be:

public String doSearch() {

   //some logic here
   String encodedSearchQuery = java.net.URLEncoder.encode( searchQuery, "UTF-8" );
   return "/path/to/page/with/multiple_results?query=" + encodedSearchQuery + "&amp;faces-redirect=true";

}

And then it should work for any character that you use.