▸JSP & Servlet/기본 상식

이클립스 / JSP / 서블릿의 인코딩(Encoding) 정리

코데방 2020. 2. 14.
728x90

[ 이클립스의 인코딩 타입 ]

 

이클립스에서 지정해주는 인코딩 타입은 파일의 저장 형식과, 저장된 파일을 읽어서 보여줄 때 사용합니다. 예를 들어 우리가 "test.java" 라는 파일을 하나 생성해서 코딩을 할 때 한글을 썼다고 해봅니다. 그럼 이클립스에서 java 파일을 저장하고 읽어올 때 설정이 "UTF-8"이라면 이 파일을 저장할 때도 UTF-8 코드로 저장하고, 읽어올 때도 UTF-8 코드로 읽어와서 문자로 변환한 뒤 우리에게 보여줍니다.

 

만약 지금 이클립스의 java 파일 인코딩 방식이 "EUC-KR"일 때 파일을 하나 저장한 뒤, 다시 인코딩 방식을 "UTF-8"로 변경하고 해당 파일을 읽어오면 공통 코드인 숫자나 영문은 멀쩡하지만 한글은 모두 깨져서 나옵니다. 따라서 A라는 사람이 이클립스 환경설정을 "EUC-KR" 인코딩 타입으로 지정해서 저장한 뒤 B에게 보내줬는데 B의 이클립스의 인코딩 타입이 "UTF-8"이라면 아래와 같이 한글 또는 다른 언어의 문자가 깨져서 보이는 현상이 발생하게 됩니다.

 

이클립스의 인코딩 타입의 경우 혼자 코딩할 때는 문제될 일이 거의 없지만 여러 사람과 협업할 때는 같이 맞춰줄 필요가 있습니다. 

 

 

환경설정에서 "EUC-KR"일 때 저장한 뒤 "UTF-8"로 바꾸고 파일을 열면 한글이 깨져보인다.

 

 

* 이클립스의 인코딩 타입 변경하기

 

1. "windows - Prferences" 탭에 들어가서 "encoding"으로 검색

 

2. "Workspace" 메뉴에 들어가서 하단의 "Text file encoding" 설정에서 타입을 변경

   - java 파일에 대한 인코딩 타입 지정

 

 

 

3. 다른 형식(JSP 등)의 기본 인코딩 타입을 변경하고 싶다면 아래쪽 탭의 설정들도 바꿔줌

   - JSP, xml과 같이 소스코드에서 파일을 어떤 형식으로 지정하고 읽을지 정해주는 경우도 있음

   - 이 경우 이클립스에서 바꿔주는 인코딩 형식은 파일을 생성할 때 설정의 기본값을 셋팅해주는 것

 

 

 


 

 

[ JSP의 인코딩 타입 ]

JSP를 작성하다보면 인코딩 설정이 들어가는 부분이 많아 매우 헷갈립니다. 순서대로 살펴보겠습니다.

 

JSP 파일은 파일 내의 코드에서 자기 자신을 어떤 인코딩 타입으로 저장할지 정해줍니다. 이클립스 환경설정에서 JSP 파일의 인코딩 타입을 바꿔주게되면 기본적으로 JSP 파일을 이클립스에서 생성할 때 인코딩 코드를 해당 타입으로 지정해서 생성해 줍니다. JSP 내의 인코딩 설정에 대해 살펴보겠습니다.

 

 

* pageEncoding 인코딩 타입

 

아래 코드에서 아랫줄에 있는 인코딩 타입입니다. pageEncoding의 인코딩 타입은 위에서 말한대로 자기 자신을 어떤 타입으로 인코딩해서 저장할지, 그리고 누군가 읽어들일때도 어떤 타입으로 디코딩해서 읽을지를 지정해주는 설정입니다. 이클립스에서 저장할 때나 읽어들일 때도 pageEncoding 타입을 확인해 인코딩해 저장하고 디코딩해 출력합니다. 또한 JVM에서 JSP를 처음 로드하기 위해 파일을 읽어들일 때도 해당 타입을 확인한 뒤 읽어들입니다. 

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>

 

코드를 읽어서 파일을 저장하고 읽을 인코딩 타입을 확인하기 때문에, 이클립스 같이 코드를 해석할 수 있는 IDE에서 생성하고 열 때는 문제가 생기지 않습니다. 남들이 어떤 타입으로 지정해뒀건 이클립스가 읽을 때 해당 타입으로 디코딩해서 출력해주기 때문입니다. 하지만 메모장 같이 일반 텍스트 파일로 만들어서 사용할 때는 이 코드를 주의해서 사용해야 합니다.

 

예를 들어 메모장 파일에서 JSP파일을 만들어 저장할 때 "ANSI" 타입으로 인코딩해보겠습니다. 대신 코드의 pageEncoding는 "UTF-8"로 설정합니다. 이 의미는 "텍스트의 내용을 ANSI코드로 변환해서 저장한다. 하지만 코드 내에서 "나는 UTF-8로 인코딩 돼있는 파일이다!" 라고 말하고 있다" 라는 의미입니다. 코드를 확인해서 저장 방식을 결정하는 IDE와 달리 메모장은 그냥 설정한대로 저장하고 코드는 그저 의미 없는 문자로 인식하기 때문입니다. 

 

 

 

그리고 이렇게 생성된 JSP 파일을 이클립스에서 열어봅니다. 여지 없이 한글이 깨져나옵니다. 이유는 이클립스가 파일을 열면서 코드를 보니 "얘는 UTF-8로 인코딩된 파일이구나" 라고 확인했기 때문에 UTF-8 타입으로 디코딩해 출력해주기 때문입니다. A를 '100'으로 변환해 저장한 파일을 읽을 때 100을 '?!'이라는 문자로 변환해주니 한글이 깨지는 것이라고 할 수 있습니다.

 

 

 

톰캣의 컨테이너가 JSP 파일을 로드할 때도 해당 코드에 설정된 인코딩 타입을 참조합니다. JVM은 코드를 읽어오면 문자열을 유니코드로 변환해서 가져오는데 이 때 해당 타입으로 디코딩해서 유니코드로 변환시켜 가져옵니다. 역시 위와 같이 메모장에서 설정을 맞춰주지 않았다면 변환된 서블릿 파일(.java 파일)의 한글 문자도 깨지게 되며 결과적으로 이걸 다시 웹으로 출력해줄 때도 인코딩 타입이 꼬여있기 때문에 이상한 문자열이 출력됩니다. 간단히 이클립스에서 JSP 파일을 열었는데 한글이 깨져서 나오면 뭔가 파일 자체의 인코딩 타입과 pageEncoding에 설정된 타입이 맞지 않는구나 생각하면 됩니다.

 

JSP에서 서블릿(.java) 파일로 변환될 때도 한글이 깨진다

 

최종 출력물에도 한글이 깨진다.

 

 


 

 

* contentType 인코딩 타입

 

위의 pageEncoding 설정이 정상적이어서 정상적인 서블릿 파일이 생성되었다고 한다면, 이 서블릿 파일은 클라이언트(브라우저)에게 html 등의 코드와 문자열을 전송해줘야 합니다. 이 때 데이터를 전송하기 위해 해당 코드와 문자열을 인코딩하는 타입을 지정해주는 부분이 contentType 입니다. 해당 인코딩 타입으로 데이터를 보내면서 http 프로토콜의 헤더에 이 타입을 명시에 주는데 브라우저에서는 이 타입으로 데이터를 디코딩해서 브라우저에 출력해주게 됩니다. 

 

HTML 코드 안에 보면 <meta> 태그에도 인코딩 타입이 또 있는데, 만약 헤더에 contentType으로 인코딩 타입이 지정돼 있다면 <meta> 태그에서 지정된 인코딩 타입은 그냥 무시합니다. <meta> 태그의 인코딩 타입은 헤더에 타입이 명시돼 있지 않은 경우에 브라우저가 참조하는 타입입니다. 

 

아래와 같이 JSP에서 <meta> 태그의 인코딩 타입을 아무거나 넣고 가동해도 정상적으로 브라우저에서 한글이 출력되는 것을 확인할 수 있습니다. 헤더의 contentType으로 인코딩 타입이 명시되어 있기 때문에 무시하는 것입니다.

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="아무거나아아아아">
<title>Insert title here</title>
</head>
<body>
	한글이로다~!
</body>
</html>

 

 


 

 

* 인코딩 타입이 지정되어 있지 않을 경우

 

[ IDE / Tomcat에서 처리]

  1. PageEncoding이 없을 경우 : contentType의 charset을 참조함
  2. contentType의 charset도 없을 경우 : 시스템 디폴트 설정을 참조함

 

[ 브라우저에서 처리]

  1.  PageEncoding은 클라이언트(브라우저)와 상관없음
  2.  contentType의 charset이 없을 경우 : <meta> 태그의 charset 참조
  3.  <meta> 태그의 charset도 없을 경우 : 브라우저 디폴트 설정을 참조함

 

 

[ 서블릿(Servlet)의 인코딩 ]

 

* POST 방식의 요청에 대한 인코딩 타입 지정

 

클라이언트에서 보낸 요청 데이터는 JSP에서 데이터를 보내줄 때 헤더에 포함했던 contentType의 인코딩 타입으로 다시 인코딩해서 서버로 보내줍니다. 없으면 후순위 타입을 참조합니다. WAS(톰캣)에서는 이 데이터를 받아서 시스템의 디폴트 인코딩 타입인 "ISO-8859-1"로 디코딩해서 request 객체를 만들어줍니다. 디폴트 인코딩 타입은 버전마다 다릅니다. 저는 Tomcat 9.0을 쓰는데 확인해보니 POST 방식은 "ISO-8859-1"이 디폴트가 맞습니다.

 

 

서블릿에서는 이 객체에서 데이터를 뽑아 자신이 처리하거나 다른 자바 클래스에 넘겨서 처리하도록 합니다. 중요한점은  현재 이 객체의 데이터는 시스템의 디폴트 설정대로 디코딩 되어 있다는 점입니다. "ISO-8859-1"은 한글을 지원하지 않기 때문에 당연히 바로 데이터를 뽑아보면 깨져서 나옵니다. 

 

그렇기 때문에 서블릿에서는 이 객체가 담고 있는 데이터를 어떤 타입으로 다시 디코딩할지 결정해줘야 합니다. 흔히들 보는 아래 메소드가 request 객체를 디코딩할 인코딩 타입을 설정해주겠다는 의미입니다. 

request.setCharacterEncoding("UTF-8")

 

Spring 같은 프레임워크를 쓰면 코드 외부에서 조금 더 편하게 인코딩 타입을 지정할 수 있도록 도와줍니다. 추후 스프링 정리할 때 추가하겠습니다.

 

 


 

 

* GET 방식의 요청에 대한 인코딩 타입 지정

 

GET 방식으로 요청이 올 때는 요청 정보가 URL 뒤에 첨부되어 전달됩니다. 아래 코드 같이 물음표 뒤에 요청 데이터(쿼리 스트링)가 URL에 첨부된 전체 주소를 URI라고 부릅니다.

http://localhost/front.do?user_name=%ED%95%9C%EA%B8%80%EC%9D%B4%EB%A6%84&user_id=codevang&user_pw=1234

 

예전 버전의 톰캣은 URI의 디폴트 인코딩 방식도 "ISO-8859-1"인걸로 아는데 제가 사용하는 Tomcat 9.0에서는 이상하게 한글이 깨지지 않고 잘 작동해서 Tomcat docs에서 찾아보니 9.0 버전에서는 URI의 디폴트 인코딩이 "UTF-8"로 되어 있었습니다. 같은 시스템이라도 버전 마다 디폴트 방식이 다르니 개발/운영 환경 등을 구성할 때 주의해야 합니다.

 

 

 

 

만약 "ISO-8859-1" 인코딩 타입을 디폴트로 사용하는 톰캣 버전이라면 아래 방법으로 디코딩 타입을 정하면 됩니다. 아래 작업은 server.xml 파일을 수정하는 작업입니다. <Connector> 태그는 서버의 서비스 포트, 프로토콜 등에 대한 연결 정보를 설정하는 태그이며 여기에 인코딩 타입을 설정해 준다는 것은 URI가 서비스 포트로 데이터를 전송하는 순간 해당 정보를 지정된 타입으로 디코딩 하겠다는 의미입니다. 디코딩 된 데이터는 역시 request 객체에 담아서 줍니다.

 

 

1. POST 객체처럼 request.setCharacterEncoding("") 메소드를 사용하도록 설정

   - useBodyEncodingForURI="true" 설정

 

server.xml 파일을 열어서 아래 코드같이 생긴 부분에 코드를 삽입해 주면 됩니다. 그럼 POST 객체 처럼 다룰 수 있습니다. Tomcat docs에서 볼 수 있듯이 이 설정을 지정하면 URI의 디폴트 인코딩 방식이 "ISO-8859-1"로 지정되고 몇 가지 방법으로 타입을 다시 지정해서 사용할 수 있게 됩니다. 비슷하게 생긴 <connector> 태그가 몇 개 보일 수 있는데 현재 사용하고 있는 서비스 포트가 지정된 태그 안에 달아주면 됩니다.

 

 <Connector useBodyEncodingForURI="true" connectionTimeout="20000" 
 port="80" protocol="HTTP/1.1" redirectPort="8443" />

 

 

 

 

 

2. 기본 URI 인코딩(디코딩) 타입을 고정해서 지정해주는 방법

   - URIEncoding="타입" 설정

 

이 방법은 모든 URI에 대한 인코딩 타입을 강제 적용하는 방법입니다. <connector> 태그 안에 코드를 넣어주면 됩니다. 저같은 경우는 이부분에 "ISO-8859-1"을 넣으니 안깨지던 한글이 깨져서 나옵니다. 이쪽 Connector도 현재 서비스 포트로 지정된 곳에 설정하면 됩니다. 

    <Connector URIEncoding="UTF-8" port="80" 
    protocol="HTTP/1.1" redirectPort="8443" />

 

728x90

댓글

💲 추천 글