request.getParameter 와 인코딩(Graha 라이브러리의 처리방법을 중심으로)
1. request.getParameter 의 인코딩에 영향을 주는 요소
1.1. file.encoding
WAS 를 기동할 때, "-Dfile.encoding=iso-8859-1" 과 같이 명령행 파라미터를 추가하지 않았다면, file.encoding 은 WAS 를 기동할 때의 환경변수에 의해 결정된다.
명령행 파라미터를 추가하기 위해서 Apache Tomcat 계열은 startup.sh 실행하기 전에 다음과 같이 JAVA_OPTS 환경변수를 설정하면 된다.
WAS 에 따라 방법이 다를 수 있다. 과거를 돌이켜 보면 startup.sh 와 같은 WAS 기동 script 에 하드코딩되어 있는 경우도 있었다.
export JAVA_OPTS="-Dfile.encoding=iso-8859-1" export JAVA_OPTS="-Dfile.encoding=euc-kr" export JAVA_OPTS="-Dfile.encoding=UTF-8"
Windows 에서 테스트한 프로그램을 Unix 로 이식한 이후에 한글이 깨지는 경우는 file.encoding 과 관련이 있을 가능성이 높다.
이 설정은 다음과 같이 확인할 수 있다.
System.getProperty("file.encoding");
1.2. request.setCharacterEncoding
request.setCharacterEncoding 를 통해 UTF-8 이나, EUC-KR 과 같은 charset 을 지정할 수 있는데 예외는 있다.
Apache Tomcat 을 기준으로 7 ~ 10 버전을 살펴보면, Apache Tomcat 7 버전의 GET 요청에서는 request.setCharacterEncoding 은 효과가 없다.
GET 요청이라고 했지만, URL 에 붙어 있는 파라미터를 의미하고, POST 요청에서도 요청 URL 자체에 파라미터를 붙일 수 있기 때문에, Graha 라이브러리는 범용적인 방법의 처리가 필요하다.
2. 시스템 설정과 무관하게 파라미터를 UTF-8로 받는 방법
2.1. Apache Tomcat 7
Apache Tomcat 7 에서 request.setCharacterEncoding("ISO-8859-1");
은 POST 에 한해서 적용된다.
Apache Tomcat 7 에서는 request.setCharacterEncoding 에 UTF-8 따위를 지정하게 되면, 파라미터가 GET 인지 POST 인지에 따라 처리를 달리해야 하므로, UTF-8 파라미터를 범용적으로 처리하기 위해서는 다음과 같이 해야 한다.
request.setCharacterEncoding("ISO-8859-1"); String param = request.getParameter("param"); param = new String(param.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
Apache Tomcat 7 의 방식은 다른 상위 버전과도 호환될 것으로 생각된다.
2.2. Apache Tomcat 8 이상
Apache Tomcat 8 이상의 버전에서는 다음으로 충분하다.
request.setCharacterEncoding("UTF-8"); String param = request.getParameter("param");
2.3. Graha 라이브러리의 처리방법
많은 WAS 를 대상으로 테스트 할 생각은 없고, Apache Tomcat 은 표준 구현체나 다름없으므로, 표준을 준수하는 다른 WAS 들도 동일한 구현일 것으로 전제하고, 다음과 같이 처리하기로 하였다.
- Server API 3.0 까지는 Apache Tomcat 7 의 방식으로 처리하고,
- Server API 3.1 부터는 Apache Tomcat 8 의 방식으로 처리한다.
if( request.getServletContext().getMajorVersion() < 3 || ( request.getServletContext().getMajorVersion() == 3 && request.getServletContext().getMinorVersion() == 0 ) ) { request.setCharacterEncoding("ISO-8859-1"); String param = request.getParameter("param"); param = new String(param.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8); } else { request.setCharacterEncoding("UTF-8"); String param = request.getParameter("param"); }
전체 소스는 QueryImpl.java 의 parameter 메소드를 참조하면 된다.
3. 테스트를 위한 소스코드
action.jsp 의 request.setCharacterEncoding 의 주석을 순차적으로 풀어보면서 테스트 한다.
3.1. form.jsp
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="UTF-8" %> <html> <head> <meta charset="utf-8"/> <meta name="viewport" content="user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, width=device-width" /> <title>Parameter Encoding</title> </head> <body> <h3>POST 전송</h3> <form method="post" action="action.jsp"> <input type="text" name="param" value="한글"> <input type="submit" value="전송"> </form> <h3>GET 전송</h3> <form method="get" action="action.jsp"> <input type="text" name="param" value="한글"> <input type="submit" value="전송"> </form> </body> </html>
3.2. action.jsp
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="UTF-8" %><% //request.setCharacterEncoding("UTF-8"); //request.setCharacterEncoding("EUC-KR"); //request.setCharacterEncoding("ISO-8859-1"); %> <html> <head> <meta charset="utf-8"/> <meta name="viewport" content="user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, width=device-width" /> <title>Parameter Encoding</title> </head> <body> <ol> <li>request.getParameter("param") : <%=request.getParameter("param")%></li> <li>request.getMethod() : <%=request.getMethod()%></li> <li>request.getServletContext().getMajorVersion() = <%=request.getServletContext().getMajorVersion()%></li> <li>request.getServletContext().getMinorVersion() = <%=request.getServletContext().getMinorVersion()%></li> <li>file.encoding = <%=System.getProperty("file.encoding")%></li> <li>java.nio.charset.Charset.defaultCharset = <%=java.nio.charset.Charset.defaultCharset()%></li> <li>request.getCharacterEncoding() = <%=request.getCharacterEncoding()%></li> </ol> </body> </html>
4. 여담
개발서버에서 개발 및 테스트를 완료했다고 하더라도, 개발서버와 운영서버의 환경이 서로 다르다면, 운영서버로 이전 한 이후에, 한글이 깨지는 등의 외관상 치명적으로 보이는 문제가 발생할 수 있다.
이런 일은 완전하게 방어할 수 있는 성질의 것이 아니지만, 최소한 다음 3개의 환경은 동일하게 유지할 것을 권한다.
- JDK 버전
- WAS 의 버전
- file.encoding 파라미터