티스토리 뷰

Web Development

[웹개발] 웹개발과 한글깨짐

§무명소졸§ 2014. 2. 13. 12:47

"영어는 잘되는데 한글은 깨져요"


자바 웹 개발자로 살아오면서 숱하게 겪고 숱하게 들어본 질문인 것 같습니다.


저 역시 많이 겪었고 인터넷 검색을 통해서 해결 해왔던것 같습니다.


하지만 웹 개발을 수년간 해오면서 진의를 파악하지 못한채 인터넷에 널린 해답지 같은 코드를 이것저것 붙여 넣

어서 "황소 뒷걸음치다 쥐 잡듯" 이 우연히 해결 했던것 같습니다.



그런데 사실을 정확하게 인지 하고 있으면 문제에 대해서 근복적으로 접근할수 있기 때문에 웹 개발하면서 한글깨짐(결국 인코딩) 에 영향을 주는 여러 요인 조각들을 두서 없이 적어 보려 합니다.


1. jsp Page Directive

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

요즘에는 좋은 템플릿 엔진들이 많이 나와서 약간 천대 받은듯 하지만 웹 개발자의 오래된 친구 JSP 입니다.
JSP 페이지에 상단부에는 늘 볼수 있는 page directive 부분 입니다. 

세개의 속성이 보이는데 UTF-8 이 2개가 보입니다. 앞에건 뭐고 뒤에건 뭐야?


1.1 pageEncoding="UTF-8"

이속성은 xxx.jsp 파일에 내용을 작성하고 저장을 하겠죠. 실제로 해당 xxx.jsp
파일 자체(저장)에 대한 인코딩 방법 입니다. 

그렇게 때문에 소스상에 하드코딩 되있는 한글에 문제가 생겼다.
1
2
3
<%
String name = "4퍎틠햤";
%>
cs

그렇다면 저부분을 의심해 볼수 있습니다. (실제로 통신간 한글문제는 저 인코딩으로는 잘 발생 하지 않습니다.)



1.2 contentType="text/html; charset=UTF-8"

아래 Html meta Tag 와 참 비슷해 보이는 놈입니다.

1
2
3
4
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
cs
하지만 저 directive 에 charset 을 바꾼다고 html meta 속성 값이 바뀌거나 그렇지 않습니다.

저 속성은 사용자가 서버로 JSP 요청을 하면 서버(WAS) 측에서 클라이언트(브라우저) 로 응답정보를 내리는 헤더 정보에 포함되는 값이 됩니다. 아래는 Http 응답통신의 Sniffing 값 입니다. (스니핑 하는법)

HTTP/1.1 200 OK

Server: Apache-Coyote/1.1

Content-Type: text/html;charset=UTF-8

Content-Length: 274

Date: Wed, 23 Apr 2014 07:10:27 GMT


--이하본문 html code 생략--

이 값이 결국 브라우저에게 이문서는 Charset이 UTF-8 인 문서임을 알려주는 겁니다.

즉 POST 방식으로 전송시 인코딩 방법을 UTF-8로 선택하게 해줍니다.

(만약 page directive 에 contentType 을 생략 한다면 html head 속해있는 meta Tag 의 charset 을 선택하게 됩니다.)



2. Get 방식요청과 한글 

브라우저에서 html 통한 문자 전송시 ISO-8859-1 charset 이외에 문자들은 인코딩이 돼서 문자가 서버 측으로 전송하게 됩니다. 그리고 서버 측은 인코딩된 문자를 받아서 다시 디코딩 하는 과정을 통해서 문자를 복원합니다.


보통 화면에서 입력한 한글이 서버에 와서 깨질 경우 이 과정을 통하는 사이에 인코딩 chatset 이 잘못되는 경우입니다.


Post는 한글이 안 깨지는데 Get 방식으로 전송하면 한글이 깨진 경우를 종종 겪을 수 있습니다. 걔다가 같은 Get 일 경우에 크롬은 되고 IE는 안될 경우도 있습니다. 왜 이런 경우가 생기는지 알아보겠습니다.


우선 크롬 브라우저로 페이지를 열고 아래처럼 Get 형태로 URL 호출합니다.


https://www.google.co.kr/?query=무명소졸



크롬의 관리자 도구로 보면 아래처럼 Request URL query 값이 인코딩 된 걸 확인할 수 있습니다.


Request URL:https://www.google.co.kr/?query=%EB%AC%B4%EB%AA%85%EC%86%8C%EC%A1%B8

Request Method:GET

Status Code:200 

Remote Address:108.177.97.94:443

Referrer Policy:no-referrer-when-downgrade



위와 같이 변경된 것을 Percent Encoding 또는 URL 인코딩 되었다고 합니다. 앞에 "%" 문자를 빼고
확인 해보면 UTF-8 3byte 16진수 코드인것을 확인 할수 있습니다. (UTF-8 한글 인코딩 확인 하로가기)

무 => EBACB4
명 => EBAA85
소 => EC868C
졸 => ECA1B8


이처럼 크롬은 기본적으로 인코딩을 charset UTF-8로 설정합니다. IE 같은 경우 EUC-KR로 하는 경우가 있고 브라우저별로 설정 옵션에 따라서 인코딩 charset 을 다르게 합니다. 

그렇기 때문에 만약 서버가 UTF-8로 인코딩 설정이 돼있다면 크롬에서는 정상적으로 되고 IE 일 경우 안되는 경우가 생기는 겁니다. 반대(서버 측 인코딩이 ecu-kr) 일 경우에는 크롬이 안될 수 있겠죠.

그렇다면 서버 측에서 Get 방식으로 전송되는 인코딩에 대한 charset 을 어디서 정할까요?

인터넷에 한글깨짐 문제의 해결책으로 수없이 많이 떠돌고 있는 was 의 config 파일인 server.xml 의 URIencoding 속성 바로 그것 입니다.

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

저 부분이 Get 방식에 대한 서버 측 인코딩 charset 설정합니다. (Post 방식의 한글 깨짐에는 해결 방법이 되지 않습니다.)


하지만 브라우저 별로 한글이 깨진다고 서버 측 인코딩 charset 설정을 바꾸거나 

또는 수많은 사용자에게 브라우저를 바꾸거나 설정을 변경하라고 할 수 없겠죠 

그래서 해결할 수 있는 방법은 서버 측 인코딩 charset 에 맞추어 클라이언트에서 문자를 인코딩해서 전송을 해주면 됩니다. 

그때 사용할 수 있는 게 아래와 같은 자바스크립트의 내장 함수 들입니다.

1
2
3
4
console.log(encodeURIComponent('무명소졸'));
console.log(encodeURI('무명소졸'));
//%EB%AC%B4%EB%AA%85%EC%86%8C%EC%A1%B8
//%EB%AC%B4%EB%AA%85%EC%86%8C%EC%A1%B8
cs


이함수를 통해서 클라이언트(브라우저) 쪽에서 인코딩해서 값을 전송 하는것이 좋은 해결 방법이 될수 있습니다.



3. Post 방식요청과 한글 

위에서 언급 했듯이 한글을 서버로 전송 할경우 인코딩 과정을 거쳐야 되고 해당 인코딩의 charset 에 설정은 요청 페이지의 응답 header 정보의 charset 또는 html meta tag 의 charset 속성정보를 따른다고 했습니다.


하지만 그렇게 인코딩을 잘해서 전송해도 서버에서는 한글 깨짐을 만나는 경우가 많습니다.

그리고 그 해결책으로 아래와 같은 방식을 많이 사용하게 됩니다.


1
2
String param = request.getParamater("name");
String name = new String(param.getBytes("8859_1"), "utf-8");
cs



그런데 분명 UTF-8 인코딩 되서 잘 보냈는데 왜 8859_1 로 인코딩 해서 다시 UTF-8을 만들까요?


그건 아래 POST 전송의 http 전문을 확인 하면 알수 있습니다.

POST /receive.jsp HTTP/1.1

Host: 127.0.0.1:8081

Connection: keep-alive

Content-Length: 32

Cache-Control: max-age=0

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8

Origin: http://10.225.149.115:8081

User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/32.0.1700.107 Safari/537.36

Content-Type: application/x-www-form-urlencoded

Accept-Encoding: gzip,deflate,sdch

Accept-Language: ko-KR,ko;q=0.8,en-US;q=0.6,en;q=0.4


name="%EB%AC%B4%EB%AA%85%EC%86%8C%EC%A1%B8"



"Content-Type: application/x-www-form-urlencoded" 


위 부분을 보면 charset 이 빠져 있습니다. 브라우저를 통해 전송할때 application/x-www-form-urlencoded media type 은 text/**** 일뿐 charset 자체를 지원하지 않기 때문입니다. 



그렇게 클라이언트에서 charset 정보를 보내지 않기때문에 서버쪽서는 클라이언트 요청 본문에 대한 encoding charset 을 알지 못합니다.

결국 default 인코딩 charset 인 ISO-8859-1으로 디코딩 되었기 때문에 한글이 깨진 상태 입니다.(실제로 http 문 전문을 변조해서 charset 을 주면 한글이 깨지지 않습니다.)

때문에 깨진 한글문자를 ISO-8859-1 로 인코딩후 다시 UTF-8 로 디코딩 해주면 정상적인 한글값을 확인 할수 있습니다.

그럼 여기서 의문이 생기는것이 모든 한글문자열에 대해서 일일히 저렇게 처리 해줘야 되는것인가? (말이 안되겠죠ㅎㅎ;)


그래서 ServletRequest API 에서는 서버 default 인코딩 charset 을 오버라이딩 할수 있는 인터페이스를 제공 합니다. 그게 바로 아래의 메소드 입니다. 

1
2
request.setCharacterEncoding("utf-8"
cs




실제로 많은 Framework 에서 인코딩 설정을 외부설정으로 빼고 있지만 내부적으로는 사실 setCharacterEncoding 메소드를 호출 하게 됩니다. 

 

 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크