네 개념을 체크해제 하세요? URL을 항상 UTF-8로 보냄 개발자로서의 Berry

부제 : 브라우저별 파라미터 인코딩방식(문자셋, charset)을 파헤쳐 보자

  오늘도 문자 인코딩방식으로 인해 한마디 해야겠습니다. 도저히 못참겠어요. euc-kr 과 자바스크립트. 파라미터 전달에 한글이 깨져요? 을 쓴지 얼마되지 않은 것 같네요. 쓸데 없는 문자 인코딩때문에 저의 소중한 하루가 날아갔으므로 오늘은 글을 꼭 쓰고 싶어졌습니다.

  결론부터 말하겠습니다. 한국의 브라우저 환경은 한마디로 난장판입니다. 브라우저 문제 중에서도 한국어 문자 인코딩 문제는 곪고 터져서 냄새가 너무 심하게 나기 때문에 반경 3650km는 접근조차 하지 못할 지경입니다. 이렇게 말도 많고 탈도 많은 문자 인코딩 문제의 밑바닥에는 EUC-KR과 UTF-8이라는 두 씨앗이 뒤엉켜 있습니다. 이 두 씨앗이 양분을 두고 서로 다투다 한 쪽이 사멸되었어야 하는데 그렇지 않고 함께 상생하며 무럭무럭 자라게 된 원인에는 개발자가 정상적인 해결방법을 찾을 생각을 하지 않고 문제를 사용자에게 throws 하여 해결한데에 있습니다. 둘 중 하나는 자연적으로 도태되어 점차 사라질 운명이 비닐하우스 속에서 양분을 받아먹고 꾸준히 살아남아온 것이죠. 개발자가 수고할 것을 사용자에게 던져 대신 처리하게 하였으니 안 그래도 잠 잘 시간 부족한 개발자님에게는 잠시 눈 좀 붙일 여유가 생기셨나봅니다. 이것 참 고마운 일이군요! 덕분에 일반 사용자도 아니고 멍청한 프로그램 개발자도 아닌 제가 눈이 시뻘게지고 있습니다. 문자 인코딩, 대체 무엇이 문제이며 무엇이 이토록 한국의 브라우저 시장을 망쳐놓고 있다는 것일까요?


  인코딩 문제는 웹 프로그래머라면 한 번씩 겪는 문제입니다. 아름다운 한글이 걸핏하면 해괴한 외계의 문자로 변해 새벽을 부르고 있습니다. 이것은 JSP, PHP, ASP 모두 예외가 아닙니다. 한글로된 페이지를 찾으니 접속이 안되고, 한글로된 파일을 다운받으려니 링크가 깨지고, 주소창에 한글을 입력했더니 아랍어가 튀어나오고 멋진 AJAX 써보려고 했더니 파라미터가 다 깨져버리고, 지식In 형님이 가르쳐준 encodeURI는 왜 안먹히는 건지 누가 좀 가르쳐주세요! 정말 답답한 일이 아닐 수 없습니다.


  컴퓨터는 문자를 비트의 값을 통해 이해합니다. 0과 1의 조합을 보고 그 값에 대응 되는 문자를 출력해주는 것이죠. 이때 글자에 따라 어떠한 비트의 조합으로 나타낼지를 결정하는 것이 바로 문자 인코딩입니다. 완성형 문자 인코딩인 EUC-KR은 '가'를 B0A1(10110000 10100001) 에 대응되며 UTF-8은 EAB080(11101010 10110000 10000000)에 대응되는 것입니다. 이처럼 인코딩에 따라 글자에 따른 비트조합이 전혀 다르기 때문에 EUC-KR 문자를 UTF-8로 읽으려한다면 안드로메다어를 체험하게 됩니다.

  그런데 그것 아시나요? 전세계 웹 환경에서 표준 인코딩은 UTF-8인 것을요. 그리고 그것도 아세요? 한국 웹 사이트들의 대부분의 인코딩은 EUC-KR이란 것을요. 저는 오늘 UTF-8과 EUC-KR은 대응되지 않는다는 단순한 이야기나 하려고 온 게 아닙니다.


혜성처럼 나타난 UTF-8

  EUC-KR은 오래 전부터 사용되어온 완성형 한글 표현방식입니다. 이에 상반되는 표현방식에는 조합형이 있었죠. 원래 완성형인 EUC-KR은 약 2400여자의 한글만을 표현할 수 있어 쀍이라던가, 휳과 같은 글자는 표현을 할 수 없습니다. 한글 창제의 원리에 따라 우리 글은 약 11,000자가 표현이 가능한데 이에 1/4도 안되는 글만 표현이 가능했던 것이죠. MS에서는 이를 확장한 코드페이지 949(이하 CP949)를 개발하여 한글이 나타낼 수 있는 모든 글자를 표현할 수 있게 되었습니다. 하지만 CP949는 완성형 방식에서 표현되지 않은 한글을 남는 비트에다가 순서대로 때려박은 식이라 한글 창제의 원리가 전혀 담겨 있지 않습니다. 완성형이 이토록 지저분한 문자인코딩임에도 1987년 우리나라에서 표준으로 정해지면서 우리 생활에는 EUC-KR이 자연스럽게 녹아나게 되었습니다. 이것은 범 세계 언어를 모두 표현할 수 있는 유니코드가 세계 표준이 되기까지 8년이나 전에 이야기입니다. 유니코드가 있었다면 이따위 빌어먹을 문자 인코딩은 쓰지도 않았을 겁니다.

  호환성은 산업계에서는 아주 중대한 이슈 중 하나입니다. 서울에서 만든 육각렌지볼트가 대구에서 만든 너트에 맞추려니 나사산의 간격이 달라 들어가지 않는다면 우리는 공장 문을 닫고 가내수공업이나 하며 살아야할 겁니다. 호환성을 위해 공통규격 즉 표준을 정하는 일은 중요한 일이 아니라 당연한 것입니다!
  컴퓨터가 전 세계에 널리 보급되고 인터넷이 아주 흔해 빠진 시절이 올 것을 예측하며 전 세계언어를 지원하기위한 문자 인코딩이 탄생했습니다. 바로 유니코드군이죠. 이 유니코드는 모든 문자에 대해 2바이트로 표현합니다. 그런데 양키들은 자기네들은 7비트만 쓰면 되는데 2바이트나 사용하는 것이 억울했는지 알파벳을 사용할 때는 1바이트만 사용하고 다국어도 지원할 수 있는 UTF-8을 만들어냅니다. 바로 이것이 UTF-8의 탄생배경입니다.  UTF-8은 1바이트부터 4바이트까지 가변적으로 늘어나면서 유니코드를 표현하는, 유니코드에 대한 또다른 표현방법입니다. 자세한 사항은 위키백과를 참조해보세요. 

  그리하여 인터넷 브라우저환경에서는 표준 인코딩이 정해졌습니다. 바로 UTF-8이죠! UTF-8은 유니코드 기반이니 이것만 있으면 전세계가 모두 글자를 제대로 표현 할 수 있겠군요! 그래서 아랍에미리트 공식 사이트를 들어가든 짱개 홈피를 들어가든 UTF-8로 인코딩 되어 있습니다. 한국만 제외하면 말이죠. 



인코딩 방식 : UTF-8. 아랍에미리트의 공식 사이트입니다. 외계어가 아니라 진짜 문자입니다.

URL을 항상 UTF-8로 보냄을 체크해제하세요?

  웹 서핑을 하다가 간혹 파일 다운로드가 안되는 경우가 있습니다. 질문 게시판에 문의하면 친절남이 웃으며 답해줍니다. 아~ 다운로드가 안되시는군요?^^ 그럼 따라하세요. [옵션]-[인터넷 도구]-[고급]-[URL을 항상 UTF-8로 보냄]을 체크해제~ 이렇게 하시면 하시면 잘되실거에요. 그래도 안되면 적용이 안된거니 브라우저 껏따 키세요. 와우 정말 멋진데요? 덕분에 사람들은 UTF-8로 보냄은 당연히 체크해제해야하는 몹쓸 녀석으로 인식하게 됩니다. 표준 규격이 한 줌의 재가 되는 순간입니다. 이봐요. 진짜 문제는 브라우저의 옵션이 아니라구요! 멍청한 개발자가 범세계 공용 문자인코딩 UTF-8을 사용하지 않고 더러운 EUC-KR로 만들었기 때문이죠!

  뿐만이 아닙니다. 멍청한 개발자들의 이 더러운 처리방식 때문에 브라우저에 까지 혼란이 왔습니다! IE에서 옵션을 변경하지 않고 주소창에 한글을 입력하면 요청을 해당 서버에 UTF-8로 보내줍니다. 친절한 설명을 듣고 옵션을 바꾼 사용자와 귀찮아 건들지도 않은 사용자가 뒤섞여 반반쯤씩 공존하고 있습니다. 파이어폭스는 주소창에 한글 파라미터를 직접 입력하면 자동으로 EUC-KR형식으로 인코딩해버립니다. 크롬은 주소창에 한글 파라미터를 입력하면 UTF-8로 보내줍니다. 이게 대체 무슨 짓이죠? 웹 표준을 지향해야 된다면서 W3C의 HTML 렌더링 표준만 중요한가요? 왜 통일된 인코딩을 사용하자는 바람은 불지 않는 걸까요.

  위에 열거했던 문제들을 다시 보죠. 한글로된 페이지 접속 실패, 한글로된 파일 다운로드 실패, 한글 파라미터 실패. 이 문제들은 사이트를 UTF-8로 만들지 않았기 때문입니다. 왜 쓸데 없이 옵션을 바꾸라고 합니까? 한글로된 페이지를 사용하지 않고, 파일명은 모두 리네임해서 사용자가 UTF-8이라는 표준환경에서도 동작할 수 있게 해줘야죠! AJAX 파라미터는 왜 깨질까요? AJAX는 요청을 날릴 때 반드시 표준 인코딩인 UTF-8로 날립니다. 이것은 자바스크립트가 포함된 페이지가 EUC-KR이든 UTF-8이든 무엇으로 인코딩되었던 관계없습니다. 그렇다보니 EUC-KR 인코딩을 사용하는 서버에서는 UTF-8로된 파라미터를 읽지 못해 오류가 나는것입니다.

  서버측에서는 GET방식의 파라미터 값만 보아서는 대체 이게 EUC-KR인지 UTF-8인지 분간을 할 방법이 없습니다. 메타 데이터도 존재하지 않고, 환경도 모두가 중구난방입니다. 정말 기가 차고 코가 막히는 일입니다. 개발자들이 UTF-8로 사이트를 구축할 생각조차 하지 않고, 더 나아가 UTF-8로 보내온 데이터를 올바르게 처리할 생각마저도 하지 않아 한국 브라우저 환경의 문자 인코딩방식은 엉망진창이 되어버렸습니다. 피부가 나빠지면 화장만 떡칠하면 나아지나요? 피부를 개선해야죠. 답답한 일입니다.



우리에겐 너무나 친숙한 문구. 대체 왜 사용자에게 문제를 throw 하는 걸까요?

소통, 그거 정치인만 하나요?

  사실 서버 내부에서만 파라미터를 주고 받고, 지지고 볶고 한다면 아무런 문제가 없습니다. 누가 URL에 직접 한글 쳐서 파라미터 값으로 검색하겠어요? 가끔 이상한 애들이 숨겨진 글이라도 보려고 할때나 쓰겠죠. 하지만 웹은 상호작용을 할 수 있습니다. 여러분의 사이트가 일방적으로 통보만 하는 것이라면 문제 없습니다. 그러나 데이터를 주고 받고 다른 사이트와 교류도 생각을 한다면 표준 인코딩인 UTF-8을 사용하세요. 나아가 브라우저 환경오염을 생각한다면 옵션을 끄라고 권하지 마세요. 웹 표준은 비단 렌더링에만 해당되는 이야기가 아닙니다. 인코딩과 같은 소소한 부분들에도 조금씩 관심을 가져주었을 때 진정한 웹 표준에 다가서는 것입니다.


실용주의 해결책 제시

  환경이 더러우니 쓰레기를 줍고 분리수거를 하는 것은 맞지만 우리는 실용주의 프로그래머입니다. 실용주의 프로그래머는 현실을 한탄하고만 있지 않죠. 더러운 환경에서도 사용자를 만족시켜야 합니다!

  EUC-KR과 UTF-8의 GET방식의 파라미터 문제에 직면한 분들은 분명 서로 다른 웹 서버간의 파라미터 전달을 주고 받고 있으시는 분들입니다. 자기 서버내부에서는 같은 문자 인코딩을 사용할테니까 파라미터가 깨지는 문제가 생길일이 없습니다! 아니면 실수이거나요. 둘중 하나죠. 이 외에는 AJAX로 인해 파라미터가 깨지는 분들이실텐데, AJAX 즉 자바스크립트 문제에 대한 솔루션은 [이 글:http://thinkberry.co.kr/623 ]에 있으니 참고하시면 됩니다.

  결론적으로 말해 GET방식이든 POST방식이든 날아온 파라미터의 인코딩방식을 확실히 알아내는 방법은 없습니다.
  POST방식의 경우 브라우저가 페이지의 charset을 보고 charset="UTF-8"이면 UTF-8로 파라미터를 날려주고 charset="EUC-KR"이면 EUC-KR로 파라미터를 날려줍니다. 하지만 이 요청을 날려주는 브라우저는 요청을 날린 페이지가 어떤 인코딩이었다는 메타데이터는 보내주지 않기 때문에 요청을 받은 서버에서는 파라미터가 무슨 인코딩 방식인지 알 수 없습니다. 만에 하나 요청을 날리는 서버가 약속된 서버이었다면 요청을 날리는 페이지에 메타 데이터를 심어 이러한 문제를 극복할 수 있습니다.<input type="encoding" value="EUC-KR" /> 한줄이면 되겠네요. 하지만 이것은 표준 방법도 아니고 서로간에 약속된 서버가 아닌 임의 서버라면 이런 메타데이터를 기대할 수 없습니다.

  GET방식은 더욱 심각합니다. 페이지마다 다르고 브라우저마다 다릅니다. 같은 브라우저인데도 EUC-KR일수도 있고 UTF-8일수도 있습니다. GET방식의 링크를 클릭한 경우와 GET방식의 URL을 주소창에 직접 입력한 경우가 서로 다른 인코딩을 보냅니다! 대체 왜 이런 차이를 둔 건지 모르겠지만 이렇다보니 브라우저 정보나 서버정보로도 무슨 인코딩인지 가늠할 수가 없습니다. 정말 답이 안나오는 겁니다.

  


파라미터의 인코딩 방식은 요청을 보내는 페이지의 charset을 따라갑니다. 단 AJAX는 무조건 UTF-8로 파라미터를 보냅니다. 표준 accept-charset 속성을 통해 인코딩방식을 지정할 수 있지만 IE에서는 작동하지 않습니다.







인코딩 방식이 EUC-KR인 페이지에서 요청을 날렸을 때 파라미터의 인코딩방식이 EUC-KR인것을 알 수 있습니다.(문자열 길이 6)







인코딩 방식이 UTF-8인 페이지에서 요청을 날렸을 때 파라미터의 인코딩방식이 UTF-8임을 알 수 있습니다.(문자열 길이 9)



  결론적으로는 이 문제에 대한 실용주의적 해결방안은 파라미터 값을 보고 인코딩을 예측해야만 합니다. MS에서 한 짓을 해야하는 것이죠. MS에서 무슨짓을 했냐구요? MS표 IE는 charset이 지정되지 않은 페이지를 어느정도 읽어들인다음 인코딩을 예측합니다.

  인코딩을 예측하는 모듈은 직접 찾아보시기 바랍니다. 지금 이자리에서는 PHP로 솔루션을 소개해드리겠습니다. 이것은 예측모듈이므로 정확성을 장담하지 않습니다. 저는 기회를 봐서 직접 개발도해볼 예정입니다. EUC-KR과 UTF-8, ASCII만 구별하면 되거든요!

  PHP에서는 mb
_detect_encoding 이라는 함수가 있습니다. 이것은 문자열을 보고 인코딩을 예측합니다. 이 함수를 사용하려면 무슨 옵션을 키고 컴파일한 PHP여야 한다는데 그부분은 직접 알아보시기 바랍니다. mb_detect_encoding함수의 시그너처는 아래와 같습니다.

 string mb_detect_encoding( string str [, string encoding list, bool strict] );

  첫번째 인자로 인코딩을 예측할 대상 문자열을 입력합니다. 두번째 인자부터는 옵션사항입니다. 두번째 인자는 예상되는 결과 인코딩 리스트입니다. 예측범위를 좁혀 정확도를 높힐 수 있습니다. 세번째 인자는 엄격성입니다. true인 경우 보다 엄격하게 검증합니다. 따라서 저는 아래와 같이 사용하였습니다.

$ac = mb_detect_encoding ($url, "ASCII, EUC-KR, UTF-8", true);


  만약 PHP로 저와 같은 문제를 겪으셨다면 위의 함수를 이용해보시기 바랍니다. 또한 위의 함수를 사용할 수 없는 다른 환경이라면 예측모듈을 직접 개발해보시거나 찾아보셔야 할 겁니다.

  오늘은 여기까지만 하겠습니다.




THinkBerry의 생각열매를 함께 나눠요. ThinkBerry.co.kr
TAG

Leave Comments


profileThinkberry에 오신것을 환영해요~ 

Recent Trackback

오늘:
4,096
어제:
3,552
전체:
76,325