Skip to content

이경민 4주차 학습일지

KyungMin Lee edited this page Jul 19, 2024 · 3 revisions

⚠️ Troubleshooting: BufferedInputStream에서 데이터를 다 읽어오지 못해요!

👾 문제상황

Java-was 프로젝트를 진행하면서 HTTP Multi Part Request에 대해서 파싱을 하고 있었습니다. 파서를 구현한 이후 사진 추가 테스트를 진행했을때 간헐적으로 에러가 발생하는 현상이 발생했습니다.

image

로그를 확인해보니 Multi Part 파싱 과정에서 오류가 있는 것이라고 판단되어 분석을 시작했습니다.

🔍 원인분석

다양한 시도를 해보던 중 사진의 크기가 약 1MB 이상인 경우 오류가 발생하는 것을 확인할 수 있었습니다.

이를 바탕으로 1MB 이상의 파일을 포함한 요청에 대해서 디버깅을 시작했습니다.

디바깅을 하던 중 이상한 점을 하나 발견했습니다. body를 받는과정에서 데이터가 누락되는 것이었습니다. image

🖥️ 원인

기존 코드는 아래와 같습니다

byte[] buffer = new byte[contentLength];
if (bufferedInputStream.read(buffer, 0, contentLength) == -1) {
    throw new HttpCommonException("요청 바디가 없습니다.", StatusCode.BAD_REQUEST);
}

BufferedInputStream에 대한 JAVADOC를 읽던 도중 read1() 메서드에서 아래와 같은 주석을 발견했습니다.

/* If the requested length is at least as large as the buffer, and
   if there is no mark/reset activity, do not bother to copy the
   bytes into the local buffer.  In this way buffered streams will
   cascade harmlessly. */

요청된 길이가 최소한 버퍼만큼 크고 마크/리셋 활동이 없는 경우, 바이트를 로컬 버퍼에 복사하지 마세요. 이렇게 하면 버퍼링된 스트림이 무해하게 캐스케이드됩니다.

BufferedInputStream를 생성할 때 설정한 버퍼 사이즈보다 큰 요청에 대해서는 처리가 안된다는 주석이었습니다.

✅ 해결

중간 버퍼를 활용하자! 라는 아이디어로 문제 해결에 도전했습니다.

기존 BufferedInputStream -> byte[] body 에서 BufferedInputStream -> byte[] buffer -> byte[] body 방식으로 중간 버퍼를 활용했습니다.

byte[] multiPartBody = new byte[contentLength];
byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
int offset = 0;
while (offset < contentLength) {
    int size;
    if ((size = bufferedInputStream.read(buffer, 0, DEFAULT_BUFFER_SIZE)) == -1) {
        throw new HttpCommonException("요청 바디가 없습니다.", StatusCode.BAD_REQUEST);
    }
    System.arraycopy(buffer, 0, multiPartBody, offset, size);
    offset += size;
}

이와 같이 수정한 이후에는 사이즈가 큰 이미지 파일을 정상적으로 파싱할 수 있었습니다 :D

👼 개인 활동을 기록합시다.

개인 활동 페이지

🧑‍🧑‍🧒‍🧒 그룹 활동을 기록합시다.

그룹 활동 페이지

🎤 미니 세미나

미니 세미나

🤔 기술 블로그 활동

기술 블로그 활동

📚 도서를 추천해주세요

추천 도서 목록

🎸 기타

기타 유용한 학습 링크

Clone this wiki locally