JAVA 2009. 11. 17. 16:30

[출처] encodeURIComponent 로 인코딩 한 후 서버로 전송했을 때 한글이 깨지는 문제.|작성자 희주




encodeURIComponent는 javascript에서 string을 UTF-8로 인코딩해주는 함수이다.

보통 http 로 주소를 전송할 때, 넘겨야 하는 변수 값 중간에 &나 #이 있으면 변수값이 제대로 전달되지 않기 때문에

인코딩을 해줘야 할 필요성이 생기는데, javascript에서 인코딩 하는 방식은 몇가지가 더 있지만,

서버에서 해석이 가능한 인코딩은 encodeURIComponent 함수를 이용하는 방법 뿐이다.

그러나 서버의 기본 문자 인코딩 타입이 UTF-8이라면 아무런 문제 없이 한글이 깨지지 않지만,

그 외의 인코딩 타입이 기본 문자셋이라면 한글이 깨지게 된다. (특히 서버가 MS949로 되어있는 경우-)

왜 깨지는 것일까-? 복원할 방법은 없는 것일까.. 를 고민했다.

문자가 깨지는 상황을 재현하기 위해 테스트 파일을 만들어봤다.

 

public void test() throws UnsupportedEncodingException {

  String a = "건강·의학";
  a = URLEncoder.encode(a, "UTF-8");
  log.info("encode : " + a);  //%EA%B1%B4%EA%B0%95%C2%B7%EC%9D%98%ED%95%99
  
a = URLDecoder.decode(a, "MS949");
  log.info("decode : " + a);  //嫄닿컯쨌?쓽?븰
  a = URLEncoder.encode(a, "MS949");
  log.info("encode : " + a);  //%EA%B1%B4%EA%B0%95%C2%B7%3F%9D%98%3F%95%99
  a = URLDecoder.decode(a, "UTF-8");
  log.info("decode : " + a);  //건강·??????

}

 

처음에 UTF-8로 인코딩 한 상태가 javascript에서 encodeURIComponent함수를 이용하여 인코딩한 결과와 같다.

그리고 서버에서는 MS949로 디코딩을 자동으로 수행하게 된다. (서버의 기본 캐릭터 셋이 MS949일 때)

그래서 결국 "건강·의학"이라는 글자는 "嫄닿컯쨌?쓽?븰" 이라는 알 수 없는 알 수 없는 글자로 깨지게 되고,

이를 다시 복구하기 위해 MS949로 인코딩을 해보았지만,

처음 javascript에서 encodeURIComponent 함수를 이용하여 인코딩 한 결과와 정확히 일치하지 않는다.(위에 빨간글자)

UTF-8로 인코딩한 한글 문자열을 MS949로 디코딩할 때는 이미 캐릭터의 byte값이 알 수 없는 정보로 저장되며,

다시 인코딩을 한다고 해서 원복이 되지 않는 것 같다.

 

해결방법은 아래 3가지이다.

1. UTF-8로 인코딩 하지 않고 그냥 전송한다.

  이 방법은 변수의 값을 온전하게 전송할 수 없기 때문에 문제가 된다.

2. MS949로 인코딩하여 전송한다.

  불행히도 javascript에서는 MS949인코딩을 지원하지 않는다.

  구글링을 해보면 개인적으로 javascript의 인코딩을 지원해주는 유틸들을 만들어서 배포한 걸 볼 수 있는데, 완벽하지 않다. 잘못 쓰면 낭패본다.;; 

  서버에서 MS949로 인코딩하여 내려보내주고, 그 데이터를 활용하면 되지만,

  html에서 script로 동적으로 생성되는 문자열을 인코딩해야 한다면, ajax를 활용해서 서버로부터 MS949변환된 문자열을 가져와야 한다.

  하지만 매번 ajax 호출이 힘든 환경도 있을 것이다..

3. encodeURIComponent 함수를 두번 사용하여 UTF-8로 두번 인코딩 한 후에 서버에서 UTF-8로 한번 더 인코딩을 한다.

  아래 코드를 참고한다.

 

 public void test() throws UnsupportedEncodingException {

  String a = "건강·의학";
  a = URLEncoder.encode(a, "UTF-8");
  a = URLEncoder.encode(a, "UTF-8");
  log.info("encode : " + a); //%25EA%25B1%25B4%25EA%25B0%2595%25C2%25B7%25EC%259D%2598%25ED%2595%2599
  a = URLDecoder.decode(a, "MS949");
  log.info("decode : " + a); //%EA%B1%B4%EA%B0%95%C2%B7%EC%9D%98%ED%95%99
  a = URLDecoder.decode(a, "UTF-8");
  log.info("decode : " + a); //건강·의학

}

 

두번 인코딩을 하기 때문에 변수 명도 길어지고, 받는 쪽에서도 디코딩을 한번은 해야 하기 때문에 그다지 나이스한 방법은 아니지만,

어쨌든 문제 해결은 되고, 코드 복잡도는 적은 편이며, 왜 이런 행위를 했는지만 잘 적어놓으면 된다. -_-;;

위와 같은 꽁수가 통하는 이유는, 영문과 숫자, %로만 이뤄진 문자열을 UTF-8로 인코딩한 문자열은

MS949로 디코딩하나, UTF-8로 디코딩하나 결과는 동일하기 때문이다.

 

인코딩의 세계는 쉽지 않다;;

 

posted by 나는너의힘
: