Translate

2016년 7월 11일 월요일

[Web] UTF-8 의 BOM 유무에 따른 한글깨짐 이슈




BOM에 대한 기본적인 정보는 위키백과(링크)를 참조하기 바란다.
(개인블로그 이긴 하지만 링크 의 경우에도 잘 정리되어 있다.)


예제파일
1. BOM file: 다운로드 링크
2. without BOM file: 다운로드 링크



도대체 BOM(Byte Order Mark) 가 어떠한 문제를 일으키는 걸까?
1004lucifer
BOM이 있는 파일은 일반적으로 문제가 되는 부분은 Linux/Unix 운영환경에서 많이 문제가 된다.
(AIX(IBM) 서버 환경에서 XML 파일에 BOM이 붙어있어서 애플리케이션이 실행이 되지 않았던 경험이 아직도 기억이 난다. 알고나면 별거 아니지만 참 고생하면서 찾았었다.)


이런 이기종 시스템에 문제가 생기지 않게 하기위해서는 BOM을 붙이지 않는게 일반적이었고 BOM을 붙이는 것에 대해서 직접적인 장점을 본적이 없었다.



최근에 BOM의 장점과 웹에 미치는 영향을 보게되어 이렇게 글을 작성한다.


증상

UTF-8 인코딩으로 된 JSON 파일을 웹서버(Apache, WebtoB etc..) 에 올려서 서비스를 하게 되었는데 웹에서 특정 파일의 한글문자가 깨지는 증상이 발생을 했다.
한글이 정상적으로 표시되는 파일은 BOM이 있었고, 한글이 깨지는 파일은 BOM이 없었다.




원인

아래의 두가지 원인이 있다. (첫번째는 BOM에 대한 직접적인 원인이 아니다.)
1. 서버에서 Response 할 시 헤더의 'Content-Type' 속성에 charset 값을 넣어주지 않는다.
2. BOM이 없으며 'Content-Type' 속성에 charset 값이 없는경우 UTF-8 인코딩으로 특별히 지정해 주지 않으면 클라이언트의 로케일(Locale) 설정을 따라간다.








원인에 대해서 분석과 해결방안을 확인해 보겠다.
(테스트는 apache-tomcat 7.0 으로 작업을 했다.)


1. 서버에서 Response 할 시 헤더의 'Content-Type' 값에 charset 값을 넣어주지 않는다.

분석
1004lucifer

1. JSP 파일의 경우 상단에
<%@ page language="java" contentType="application/json; charset=utf-8" pageEncoding="utf-8"%>
문자열을 입력 시 별다른 서버 작업 없이
Response 헤더에 Content-Type: application/json;charset=utf-8 값으로 내려오며 한글이 정상적으로 보여졌다.

2. txt, json 등등 jsp 가 아닌 다른 파일에 대해서는 위의 작업을 할 수 없다.



해결방안 (jsp 가 아닌 파일에 대해서)


1. WEB에서 서비스 하는경우 WEB 애플리케이션에 따라 설정해 준다.
 ex) Apache - .htaccess 파일 설정 (아래의 3개의 설정중에 취행대로 설정해 주면 된다.)
1. AddDefaultCharset utf-8
2. AddType 'application/json; charset=UTF-8' .json
3. AddCharset utf8 .json
apache 설정: 링크1, 링크2


2. WAS에서 서비스 하는경우 web.xml 파일에 아래와 같이 해당 확장자에 대해서 mime-type 을 지정해 준다.
<mime-mapping>
        <extension>json</extension>
        <mime-type>application/json; charset=utf-8</mime-type>
</mime-mapping>


PS.
WAS에서 서비스 하는경우 web.xml 을 사용하지 않는경우 해결을 할 수 없을 수 있다.
(WAS에서 web.xml 을 사용하지 않는경우는 여러가지 경우가 있을 수 있는데 Web 서버 없이 WAS 단독 구성으로 되어있는 상황에서 특정 디렉토리를 alias 걸어서 사용하면 web.xml 이 없는 상황이 되어버린다.)
  ex) Tomcat 에서는 web.xml 을 사용하지 않으면 방법이 없다.






2. BOM이 없으며'Content-Type' 속성에 charset 값이 없는경우 UTF-8 인코딩으로 특별히 지정해 주지 않으면 클라이언트의 로케일(Locale) 설정을 따라간다.

분석
1004lucifer

1. Windows OS에서 'Content-Type' 속성에 charset 값이 없을 때 BOM 있는 파일의 경우 한글이 정상적으로 표시되며, BOM 없는 파일의 경우 한글이 깨졌다.
(UTF-8 Locale을 사용하는 Ubuntu에서는 둘다 한글이 정상적으로 보여졌다.)

BOM 있는 파일






BOM 없는 파일






Android 핸드폰의 경우에도 BOM 없는 파일의 한글이 깨졌으나 아래와 같이 설정을 변경 후 새로고침을 하니 정상적으로 보여졌다.
* 브라우저 설정 => 고급 => 텍스트인코딩
(핸드폰에 따라 설정 방법이 조금 다를 수 있다.)







해결방안


1. 위와 같이 이미 만들어진 프로그램(브라우저 같은..)의 경우에는 다음과 같이 할 수 있다.
  1) 'Content-Type' 속성에 charset=utf-8 이 나올 수 있도록 서버 설정을 변경한다.
  2) 파일에 BOM 을 붙인다. (권장하지 않음.)

2. 프로그램을 직접 제작/수정 하는경우 HTTP프로토콜을 이용해 해당 Resource를 받아올 시 UTF-8 인코딩을 지정한다.
  1) HttpClient (apache) 라이브러리
    - 별다른 설정 없이 기본으로 UTF-8을 지원하는지 한글이 깨지지 않는다.
  2) Spring RestTemplate 라이브러리
    - StringHttpMessageConverter 객체를 아래와 같이 생성 해야 한다. 그렇지 않은경우 구동되는 시스템 Locale을 따라간다.
new StringHttpMessageConverter(Charset.forName("UTF-8"))






PS.
BOM에 대한 고찰

RFC4627(링크) 문서에 보면 JSON Text 는 유니코드로 인코딩 되어야 하며 Default 로 UTF-8 을 사용한다고 정의되어 있다.
그렇다는건 현재 사용되어지는 브라우저 또한 'Content-Type' 값이 'application/json' 으로만 지정되어 있어도 알아서 UTF-8 로 인코딩하여 정상적으로 보여줘야 한다고 생각한다.

현재 사용하는 Chrome 51.0 버전과 Android 5.0.2 단말기의 브라우저에서 알아서 UTF-8 로 파싱해서 보여주고 있지 않고 있다.





참고
http://blog.wystan.net/2007/08/18/bom-byte-order-mark-problem
http://stackoverflow.com/questions/477816/what-is-the-correct-json-content-type
http://serverfault.com/questions/581760/how-do-i-set-proper-headers-for-json-in-apache
http://www.ietf.org/rfc/rfc4627.txt


댓글 없음 :

댓글 쓰기