If you have a Web application with HTML forms and your form data are encoded with a charset other than the default charset (ISO-8859-1), odds are that your form data will not be properly decoded when they are accessed as request parameters. The reason for this encoding/decoding mismatch is that most browsers do not properly handle the Content-Type header. The HTTP specification defines a Content-Type request header that browsers can use to specify request encodings, but most browsers never set this request header. Because of this oversight, a page specified as a form's action will assume that the form's request parameters were encoded with the default charset (ISO-8859-1) and attempt to decode the request parameters with that encoding. If the request parameters were encoded with a charset other than ISO-8859-1, they will not be properly decoded by the form's action. Let's examine the Web application shown in Figure 7-6 to see how Internet Explorer 6.0 fails to properly decode request parameters generated by forms with a charset other than ISO-8859-1. Figure 7-6. Reading Request Parameters from Forms with a Chinese Charset
The Web application shown in Figure 7-6, localized for Chinese, consists of two JSP pages, one containing a simple form that asks for a user 's name and another that tries to display the name that was entered in the form. The JSP page containing the form is listed in Listing 7.21. The preceding JSP page uses the JSP page directive to set the Content-Type header, specifying Mainland Chinese (GB2312) for the response charset. This is verified by the <c:out> action at the bottom of the page, which prints the character encoding for the page's response. As you can see from Figure 7-6, the response charset for the preceding JSP pages is indeed GB2312. The action for the form in the preceding JSP page is show_parameters.jsp , which is listed in Listing 7.22. The preceding JSP page sets its response charset to Mainland Chinese (GB2312) and tries to display the name request parameter, but as you can see from Figure 7-6, that request parameter is not properly decoded. Subsequently, the preceding JSP page prints its request encoding, which is null , and therefore the <c:out> action displays nothing. Listing 7.21 index.jsp<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html> <head> <title>Broken Request Decoding</title> </head> <body> <%@ taglib uri='http://java.sun.com/jstl/core' prefix='c'%> <%@ taglib uri='http://java.sun.com/jstl/fmt' prefix='fmt'%> <%-- Set the charset for this page's response to GB2312 (Chinese) --%> <%@ page contentType='text/html; charset=GB2312' %> <%-- Set the locale for <fmt:message> actions to zh (Chinese) --%> <fmt:setLocale value='zh'/> <%-- Set the bundle basename for <fmt:message> actions --%> <fmt:setBundle basename='app'/> <fmt:message key='login.form.title'/><hr> <form action='show_parameters.jsp'> <table><tr> <td><fmt:message key='login.textfield.name'/></td> <td><input type='text' name='name' value= '<fmt:message key="login.textfield.nameValue"/>'/> </td> </tr></table> <br> <input type='submit' value='<fmt:message key="login.button.submit"/>'/> </form> <%-- Show the response's charset --%> Response Charset: <c:out value='${ pageContext.response.characterEncoding }'/> </body> </html> Listing 7.22 show_parameters.jsp<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html> <head> <title>Broken Request Decoding</title> </head> <body> <%@ taglib uri='http://java.sun.com/jstl/core'prefix='c'%> <%-- Set the charset for this page's response to GB2312 (Chinese) --%> <%@ page contentType='text/html; charset=GB2312' %> <p>Name: <c:out value='${param.name}'/> <%-- Show the request charset --%> Request Charset: <c:out value='${ pageContext.request.characterEncoding }'/> </body> </html> Because the JSP page containing the form specified its response charset as GB2312, and because that form invoked the preceding JSP page, the request charset for the preceding page should also be GB2312. But as you can see from Figure 7-6, that's not the case. Servlet developers have long been aware of this problem, and they have come up with a workaround: they store the response charset for the JSP page containing the form in a session attribute. Before it decodes request parameters, the JSP page specified as the form's action sets its request charset to the value of that session attribute; for the preceding example, it would work like this: <%-- This is from the JSP page containing the form --%> ... <%-- Store the request charset in a session attribute--%> <c:set var='requestCharset' value='GB2312' scope='session'/> ... <form action='show_parameters.jsp'> ... </form> ... <%-- This is from the JSP page specified as the form's action --%> <% <%-- Retrieve the request charset from the session attribute--%> String charset = (String) pageContext.getAttribute("requestCharset", PageContext.SESSION_SCOPE); <%-- Set the request character encoding with the value of the session attribute--%> request.setCharacterEncoding(charset); %> ... <%-- Now the request parameters will be decoded properly --%> ... To save you the trouble of implementing the workaround listed in the preceding code fragment, JSTL does it for you. Whenever JSTL locates a resource bundle, it stores the charset corresponding to that resource bundle's locale in a configuration variable named javax.servlet.jsp.jstl.fmt.request.charset in session scope. You can use the <fmt:requestEncoding> action to set the request encoding for your JSP page to the value of that session attribute. Here is the syntax of that action: [20]
<fmt:requestEncoding [value]/> If you don't specify a value for <fmt:requestEncoding>, the action works as described above, by setting the request encoding to the value of the javax.servlet.jsp.jstl.fmt.request.charset session attribute. Alternatively, you can explicitly specify the charset value with the value attribute. Figure 7-7 shows the same application shown in Figure 7-6 on page 288, except that show_parameters.jsp uses the <fmt:requestEncoding> action to set its request encoding. Figure 7-7. Using <fmt:requestEncoding>
Listing 7.23 lists show_parameters.jsp , revised to use the <fmt:requestEncoding> action. Listing 7.23 show_parameters.jsp (revised) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html> <head> <title>Using <fmt:requestEncoding></title> </head> <body> <%@ taglib uri='http://java.sun.com/jstl/core'prefix='c'%> <%@ taglib uri='http://java.sun.com/jstl/fmt' prefix='fmt'%> <%-- Set the charset for this page's response to GB2312 (Chinese) --%> <%@ page contentType='text/html; charset=GB2312' %> <%-- The <fmt:requestEncoding> action sets the incoming request's charset to match the response charset of the referring page. Since we know the charset is GB2312, we could have specified it with the value attribute, like this: <fmt:requestEncoding value='GB2312'/> --%> <fmt:requestEncoding/> <p>Name: <c:out value='${param.name}'/> <%-- Show the request and response charsets --%> <p>Request Charset: <c:out value='${pageContext.request.characterEncoding}'/> </body> </html> |