[Java] InputStreamReader가 UTF-8로 decode를 해도 한글 변환이 안되는 이유

nathan·2022년 7월 24일
0

JAVA

목록 보기
44/45

오늘은 박재성님의 Next Step 스터디를 진행 중에 겪었던 문제인
Java의 InputStreamReader가 UTF-8로 decode를 해도 한글 변환이 안되는 이유에 대해서 알아보고자 합니다.

글 내용 중 잘못된 부분이 있거나 질문이 있으시다면, 언제든 댓글 주시면 감사하겠습니다! 🙏


목차

  • 문제 인식
  • 원인 분석
  • Reference

문제 인식

Next Step의 3장 HTTP로 통신하는 웹서버를 구현하는 미션을 진행 중에 있었습니다.

흐름

기존 Base code가 HTTP Request를 InputStream으로 받아오는데,
이를 InputStreamReader로 읽고 BufferedReader로 읽습니다.

문제

InputStreamReader의 생성자 파라미터에 StandardCharsets.UTF_8을 넣어주었는데도,
HTTP Request Message에 있는 한글이 decode 되지 않는 상태로 들어오는 문제가 발생했습니다.

기존 코드 (RequestHandler의 run() 메서드)

    public void run() {
        log.debug("New Client Connect! Connected IP : {}, Port : {}", connection.getInetAddress(),
                connection.getPort());

        try (InputStream in = connection.getInputStream(); OutputStream out = connection.getOutputStream()) {
            // TODO 사용자 요청에 대한 처리는 이 곳에 구현하면 된다.
            InputStreamReader inputStreamReader = new InputStreamReader(in, StandardCharsets.UTF_8);
            BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
            
			log.debug("RequestLine ={}", bufferedReader.readLine());
            DataOutputStream dos = new DataOutputStream(out);
            byte[] body = "Hello World".getBytes();
            response200Header(dos, body.length);
            responseBody(dos, body);
        } catch (IOException e) {
            log.error(e.getMessage());
        }
    }
  • 상황 가정 : http://localhost:8080/user/create?userId=nathan&password=123123&name=나단&email=nathan@velog.io를 GET 요청받는다.

  • 위 코드에서 log.debug("RequestLine ={}", bufferedReader.readLine());이 부분이 실행되면 아래와 같이 들어오게 된다.

    HTTP method : GET
    URI path : /user/create?userId=nathan&password=123123&name=%EB%82%98%EB%8B%A8&email=nathan@velog.io
    HTTP version : HTTP/1.1

  • 분명 InputStreamReader 생성자에 StandardCharsets.UTF_8을 넣어 주었음에도 불구하고, name 부분에 나단이 아닌, %EB%82%98%EB%8B%A8가 들어오는 것을 확인할 수 있다.


원인 분석

원인 분석

  • InputStreamReaderBufferedReader가 InputStream을 처리하는 데이터의 길이 단위는 1byte인데, UTF-8로 디코딩을 하게되는 경우 한글은 한 글자에 3byte를 차지한다.
    • 여담으로 EUC-KR 인코딩을 쓰면 한글은 한 글자에 2Byte를 차지한다.
  • 따라서, BufferedReader로 한 Line을 받아 온 데이터 전체를 다시 decoding 해주어야 한다. (by URLDecoder)

개선 코드

    public void run() {
        log.debug("New Client Connect! Connected IP : {}, Port : {}", connection.getInetAddress(),
                connection.getPort());

        try (InputStream in = connection.getInputStream(); OutputStream out = connection.getOutputStream()) {
            // TODO 사용자 요청에 대한 처리는 이 곳에 구현하면 된다.
            InputStreamReader inputStreamReader = new InputStreamReader(in, StandardCharsets.UTF_8);
            BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
            
			log.debug("RequestLine ={}", URLDecoder.decode(bufferedReader.readLine(), StandardCharsets.UTF_8));
            DataOutputStream dos = new DataOutputStream(out);
            byte[] body = "Hello World".getBytes();
            response200Header(dos, body.length);
            responseBody(dos, body);
        } catch (IOException e) {
            log.error(e.getMessage());
        }
    }

URLDecoder.decode(bufferedReader.readLine(), StandardCharsets.UTF_8))

  • URLDecoder의 decode 메서드를 통해 한글로 변환이 제대로 됨을 확인할 수 있었다!
    • http://localhost:8080/user/create?userId=nathan&password=123123&name=나단&email=nathan@velog.io

Reference

profile
나는 날마다 모든 면에서 점점 더 나아지고 있다.

4개의 댓글

comment-user-thumbnail
2022년 7월 24일

이열 냐하~~ 잘 보고 가요우~~

1개의 답글
comment-user-thumbnail
2022년 7월 24일

나단 열심히 하시는 거 같아요~ 👍👍
잘 보구 가요!

1개의 답글