아파치와 톰캣이 각각 별도로 구성되어 있는 환경에서 GET 요청을 처리하는 API를 만들었다. 파라미터로 한글을 받는데 이게 계속 깨져서 들어왔다. 결국 해결했는데 반나절을 꼬박 날려버려서 해결하는 과정에서 알게된 사실들을 기록한다.
URL에 포함된 한글 파라미터는 반드시 인코딩을 할 필요는 없다. 기본적으로 인코딩 하지 않아도 http 프로토콜 내에서 자동으로 인코딩 된다. 명시적으로 인코딩이 필요한 경우는 공백이나 특수문자가 포함된 경우이다. 다만 인코딩을 해서 보내면 아파치에서 그걸 그대로 읽어들이지만 인코딩을 하지 않을 경우 한글을 바이트배열로 인코딩한다.
아무튼 이런 상황에서 톰캣의 server.xml 파일에는 Connector URIEncoding 이 UTF-8로 잘 되어 있었는데 컨트롤러에서 한글파라미터가 계속 깨져서 나왔다. 참고로 한글 파라미터는 "싸이월드" 이다.
깨져서 표기되는 값은 ì¸ì´ìë 였는데 수동으로 인코딩과 디코딩을 해보니 대략 아래와 같은 과정에서 이런 문자열이 생성되는 것을 파악했다. 즉, UTF-8로 인코딩 되었는데 ISO-8859-1 로 디코딩을 한 것이다.
String str = "싸이월드";
str = URLEncoder.encode(str, "UTF-8");
str = URLDecoder.decode(str, "ISO-8859-1");
System.out.println(str);
그런데 신기한 것은 이런 현상이 한글 파라미터를 UTF-8로 인코딩해서 보내도 인코딩 하지 않고 보내도 동일하게 발생했다. 참고로 인코딩을 하지 않고 보내는 것은 CURL 을 활용했다. intellij 의 http 나 브라우저에서의 요청은 기본적으로 URL이 UTF-8로 인코딩되어 요청되기 때문이다.
톰캣에 설정된 URIEncoding 이 UTF-8 로 되어 있기 때문에 마지막에 UTF-8 로 디코딩이 수행되는건 확실하다. ISO-8859-1 로 디코딩이 정상적으로 수행되었다면 추가 디코딩으로 변화가 없을 것이기 때문에 대략 아래와 같은 과정을 짐작할 수 있었다.
String str = "싸이월드";
str = URLEncoder.encode(str, "UTF-8"); // ??
str = URLDecoder.decode(str, "ISO-8859-1"); //아파치 디코딩
str = URLDecoder.decode(str, "UTF-8"); //톰캣 디코딩
System.out.println(str);
수동으로 UTF-8 인코딩을 하지 않았는데도 위와 같은 현상이 발생하는 걸로 보아 어딘가에서 자동으로 인코딩을 해준다고 밖에 생각할 수 없었다. 그런데 나는 CURL로 호출했는데 대체 어느단계에서 인코딩을 해준단말인가..
혹시 CURL 에서 해주나 싶었는데 아파치 로그를 보면 바이트배열로 찍힌다..그렇다면 아파치-톰캣 구간에서 인코딩/디코딩이 수행되는건가?
내가 내린 결론은... 아파치에 도달하기 전 http 프로토콜 내에서 UTF-8 로 인코딩 되었고 그걸 ISO-8859-1 로 디코딩 하는 과정에서 한글이 깨지는 현상이 발생했다. 이는 아파치의 기본 디코딩이 ISO-8859-1 이기 때문이다.
이를 해결하는 방법은 3가지 이다.
1. httpd.conf 파일에 AddDefaultCharset [케릭터셋] 설정으로 디코딩을 UTF-8로 바꾸는 방법
2. 요청할 때 Content-Type 헤더에 charset=UTF-8을 지정하는 방법. 이렇게 되면 아파치에서 해당 케릭터셋을 디코딩에 활용한다.
3. ISO-8859-1 로 디코딩 되어 있는 값을 컨트롤러 소스에서 다시 UTF-8 인코딩으로 되돌린 뒤에 디코딩 하는 방법
new String(iso.getBytes("ISO-8859-1"), "UTF-8")
이 중 내가 선택한 것은 3번이다. 나만 수정하면 되니까...
https://codevang.tistory.com/196
'Backend > Http+Servlet' 카테고리의 다른 글
한글 인코딩과 new String, getBytes (0) | 2021.07.16 |
---|---|
Contents-Type, Accept (0) | 2021.04.20 |
서버에서 클라이언트 Cookie 셋팅하기 (0) | 2021.03.29 |
JSESSIONID (0) | 2021.03.29 |
response.sendRedirect 에 대한 오해 (2) | 2021.03.16 |