JSP charset

programing/JAVA 2009.08.14 12:23

*JSP에서의 인코딩

JSP 문자 인코딩은 컨테이너가 JSP파일을 JAVA로 변경하기위해 읽어들일때, 해당 JSP파일이 어떤 문자셋으로 이루어져 있는가를 컨테이너에게 알려주기 위해 JSP page 지시자에 선언되어 있는 캐릭터셋이다.

JSP 파일의 문자 인코딩 캐릭터셋은 JSP page 지시자의 속성중에 pageEncoding를 확인하면 된다. ContentType에서 인코딩을 정의 하지 않았을 경우 default 값인 ISO-8859-1이 설정된다.


예를 들어 다음과 같은 내용의 JSP파일을 생성하였다고 가정하자. (파일 인코딩은 UTF-8이라고 가정한다)

 

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="EUC-KR"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>
테스트</title>
</head>
<body>
<div>
    <form action="/test2.jsp" method="post">
        <input type="text" name="keyword" > <input type="submit">
    </form>

</div>
</body>
</html>


다음은 위의 JSP 파일이 변경된 JAVA 파일의 일부이다.

 

out.write("\r\n");
      out.write("<head>\r\n");
      out.write("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\r\n");
      out.write("<title>
�����
/title>\r\n");
      out.write("</head>\r\n");
      out.write("<body>\r\n");
      out.write("<div> \r\n");
      out.write("\t<form action=\"/test2.jsp\" method=\"post\">\r\n");
      out.write("\t\t<input type=\"hidden\" name=\"actions\" value=\"test2\" >\r\n

 

JSP <title>의 한글이 깨져 있음을 확인할 수 있다.

 

page 지시자에는 pageEncoding 뿐만 아니라 contentType 이라는 속성도 있는데, 이 속성은 MIME 타입과 해당 페이지에서 사용될 인코딩 문자셋을 설정한다. , 이 값에 따라 브라우져가 서버의 메시지를 어떤 문자셋으로 해석할지가 결정되며, 페이지에서 사용되는 문자들의 인코딩 문자셋이 결정된다. 대부분의 브라우져의 기능을 살펴보면 문자 인코딩을 변경하는 메뉴가 있는데, 여기에 기본으로 선택된 값이 contentType에 설정된 값이다.

contentType 이 생략될 경우 pageEncoding 값을 따르며, pageEncoding 까지 생략되면 기본적으로 ISO-8859-1 문자셋을 따른다.

 

예를 들어 contentType의 값이 UTF-8 이라면 클라이언트의 브라우져는 서버의 응답을 UTF-8로 해석하여 HTML 파일을 화면에 뿌리게 된다. 그리고 페이지의 모든 문자들은 UTF-8의 문자셋을 기반으로 하게된다.

 

HTML meta 태그내의 content 속성은 단순히 메타 태그로써 페이지의 정보를 알려주는 기능외에 실제 인코딩에 관여하지 않는다는 것에 주의하도록 한다.

 

서블릿과 톰캣 인코딩

톰캣은 클라이언트에서 서버로의 요청메시지를 서블릿 스펙에 따라 기본적으로 ISO-8859-1 로 인코딩되어 처리되도록 되어 있다. , 클라이언트에서의 문자열이(contentType) UTF-8 이든, EUC-KR 이든 ISO-8859-1로 인코딩 된다는 것이다.

(메시지의 인코딩은 앞에서 언급한바대로 웹페이지의 ContetType 값에 따른다)

 

, 다음의 코드가 실행되는 것과 같다.

//UTF-8 인코딩된 메시지
new String( "UTF-8".getByte("UTF-8"),"ISO-8859-1");

//EUC-KR
인코딩된 메시지
new String("EUC-KR".getByte("EUC-KR"),"ISO-8859-1");

한글 처리를 위한 UTF-8이나 EUC-KR 2바이트 문자인데, 1바이트 문자인 ISO-8859-1로 인코딩하면 문자열이 깨어지는 것처럼 보이지만 실제로는 문자열의 바이트값이 보존된다. 여기서 인코딩/디코딩의 개념과 ISO-8859-1 이라는 문자셋에 대한 이해가 필요하다.

 

우선 문자셋이라는 것은 글자와 바이트의 매핑관계를 정의하는 것으로 문자셋에 따라 이 매핑관계가 달라진다.

예를 들어 EUC-KR문자셋에서 "테스트" 라는 문자열은 "c5d7bdbac6ae" 바이트배열값으로 매핑된다.

이때 EUC-KR 문자셋은 2바이트 문자셋이므로 c57b값이 "" 라는 문자열값에 매핑되며 7bdb c6ae는 각각 "" ""에 매핑이된다.

이렇게 문자열을 바이트 시퀀스로 변환하는 과정을 인코딩, 그 반대 과정을 디코딩이라고 한다.

 

이론적으로 EUC-KR 2바이트 문자로써 65535개의 문자를 매핑하는것이 가능하지만 실제로는 대부분의 바이트가 비어있다. 이는 UTF-8이나 KSC5601, MS949 등 마찬가지이다. 문자셋들은 동일한 바이트값에 대한 매핑문자가 서로 다르며, 문자 구성또한 달라 매핑이 불가능한 문자도 있다. 예를 들어 유니코드 "" 문자를 EUC-KR 로 인코딩할경우 "" 문자가 EUC-KR 문자셋에 정의되어 있지 않으므로, 자바는 이를 "?(0X3F)"로 변경해버린다. "?"로 매칭된 문자는 원래의 유니코드로 디코딩된다고 해도 원래의 "" 문자를 표현하지 못하게된다. 이처럼 문자간의 인코딩/디코딩시에 데이터 손실이 일어나게되는데, ISO-8859-1 문자셋은 1바이트로 이루어져있지만, 유일하게 빈공간없이 모든 바이트값에 대해 문자를 매핑하고 있다. 따라서, ISO-8859-1 문자셋으로 인코딩되었다하더라도 원래 문자셋으로 디코딩만 하면 데이터의 손실없이 원래의 문자를 표현할수 있게된다.

 

다시 톰캣이야기로 돌아가서 위에서 언급하길 서블릿 스펙에 따라 톰캣은 모든 요청메시지를 ISO-8859-1로 인코딩한다고 하였다.

, EUC-KR 문자열의 바이트 값인 "c5d7bdbac6ae"를 톰캣이 받게되면 이 바이트 배열을 ISO-8859-1 문자셋으로 인코딩된것으로 간주하고 ISO-8859-1문자셋을 이용해 디코딩해버린다. 그렇게 되면 "c5d7bdbac6ae" 바이트배열은×½ºÆ®" 이라는 문자열로 디코딩되는데, ISO-8859-1문자셋은 각 바이트에 매칭되는 문자값이 모두 존재하기때문에 의미없는 문자로 표현될지언정 매칭문자가 없어 "?"로 표현될 일이 없다. , 문자열이 깨지지 않는다. 따라서, "Å×½ºÆ®" 문자열을 다시 EUC-KR 문자셋으로 인코딩하게되면 원래의 문자열로 돌아가게되는것이 보장된다.

 

byte[] bytes = "테스트".getBytes("EUC-KR");
String str = new String(bytes,"ISO-8859-1");
System.out.println(hex(bytes)); //hex()
는 바이트 배열값을 HEX코드로 출력하는 기능

System.out.println(str);
bytes = "Å×½ºÆ®".getBytes("ISO-8859-1");
str = new String(bytes,"EUC-KR");
System.out.println(hex(bytes));
System.out.println(str);
=============================================
c5d7bdbac6ae
Å×½ºÆ®
c5d7bdbac6ae
테스트


톰캣으로 전달된 ISO-8859-1 인코딩된 데이터는 톰캣 내부에서 사용자의 요청메시지를 처리하기위해 request 객체를 생성하는 과정에서 인코딩 과정을 거치게된다. 이때 적용되는 인코딩 문자셋은 기본적으로 null로써 시스템 프로퍼티인 file.encoding에 정의된 인코딩 문자셋(이하, 시스템 인코딩 문자셋)을 사용하도록 되어 있다. 클라이언트의 요청메시지의 원래 인코딩 문자셋과 시스템 인코딩 문자셋이 다르다면 원래의 문자셋으로 복원이 불가능해지므로 한글 인코딩이 깨어지게 된다. 따라서 한글 데이터를 보존하기 위해서는 new String("문자열".getByte("ISO-8859-1"), "EUC-KR") 같이 클라이언트에서 전송시에 사용된 문자셋으로 디코딩 과정을 먼저 실행한다음 원래대로 문자열을 복원하여야 한다. 번거로운 인코딩작업 대신에 클라이언트의 요청 메시지 전체에 대해 명시적으로 인코딩 문자셋을 지정해주는 방법이 있는데, 그 방법은 아래와 같다. (단 인코딩 문자셋은 request 객체가 생성되기전에 정의되어야 한다)

request.setCharacterEncoding("문자셋이름")

 

톰캣은 클라이언트의 요청메시지에 대한 request 객체의 생성이 끝나면, 응답 메시지를 작성하기위해 response 객체를 생성하게 된다. 이때 response 객체의 생성시에 사용되는 인코딩 문자셋은 JSP 파일의 page 지시자의 contentType 속성에 정의된 인코딩 문자셋을 따르게 된다. 서버의 응답 메시지를 생성할때 사용되는 인코딩 문자셋과 브라우져에서 이를 해석하는 문자셋이 항상 contentType을 따르도록 되어있으므로 프로그래머는 이 단계에서는 인코딩에 대해 신경쓰지 않아도 된다. 하지만 문제는 request 객체와 response 객체 사이에서 일어난다. 대부분의 응답메시지는 요청메시지의 데이터를 포함하게 되는데, 요청메시지에 대해 디코딩을 완벽하게 수행했다하더라도, request 객체와 response 객체의 인코딩 문자셋이 다르다면 request 객체의 데이터가 response 객체에서 인코딩이 깨어지게 된다.

 

이렇게 생성된 서버의 응답메시지는 ISO-8850-1 인코딩되어 클라이언트의 브라우져에 전달된다. 전달된 응답 메시지는 클라이언트의 브라우져에서 contentType에 정의된 인코딩 문자셋을 이용하여 해석된 다음 출력되게 된다.

 

GET POST

앞절에서 클라이언트 요청메시지에 전체에 대해 명시적으로 인코딩 문자셋을 지정하는 방법을 소개하였다. 하지만 이 경우 request 객체가 생성되기 이전에 인코딩 문자셋을 지정하여야 하므로 톰캣에서는 필터를 사용하여 인코딩 문자셋을 지정할 것을 권장하고 있다. 하지만 이 경우에도 약간의 문제가 있다. 클라이언트의 요청메시지는 GET POST 두 가지 방식으로 서버에 전달되는데, 필터에 의한 인코딩 문자셋을 지정하는 방법은 POST요청에 한해서만 유효하다는 점이다. GET 방식으로 전달 되는 파라메터는 URL에 포함되어 전달되는데, URL은 요청 메시지 내부의 파라메터는 지정된 인코딩 문자셋을 사용하지않고 기본적으로 ISO-8859-1 인코딩 문자셋에 따라 해석을 하기 때문이다. 따라서 URL에 대한 인코딩 문자셋을 명시적으로 지정해줄 필요가 있다. 이를 위해서는 톰캣의 tomcat_home/conf/server.xml 파일의 Connector 부분의 설정을 변경하여야 한다

 

 ...
    <Connector ... port="8080" URIEncoding="UTF-8" />
...

 

정리

지금 까지의 이야기를 정리하자면 한글을 적절하게 처리하기 위해서는 우선, 요청 페이지의 contentType을 확인해야 하며, 사용자의 요청메시지가 GET인지, POST인지를 확인한다. 그런다음 각각의 요청메시지 타입에 따라 서버에서 메시지를 처리하는 인코딩 문자셋을 확인한 다음, 마지막으로 응답 페이지의 contentType을 확인하여 이 4가지 인코딩 문자셋이 일치하는가를 살펴보아야 한다.

저작자 표시 비영리 동일 조건 변경 허락
신고

'programing > JAVA' 카테고리의 다른 글

THE Elements OF java Style  (1) 2009.08.31
java & jsp 개발 팁  (0) 2009.08.19
JSP charset  (0) 2009.08.14
HTML A태그, IMG태그 추출  (1) 2009.06.22
HTML 태그제거 소스  (0) 2009.06.22
계층형 게시판  (0) 2009.06.03
Posted by 대절님
TAG

댓글을 달아 주세요



티스토리 툴바