본문 바로가기

개발/백앤드

[2] 인X타그램에서 게시물 작성 시 어떤일이 일어날까? - multipart/form-data편

HTTP의 ‘multipart/form-data’는 이미지, 텍스트, 비디오 등을 단일 HTTP 요청으로 전송할 수 있다는 이점이 있다.

 
 
 

파일 업로드와 파일 업로드 정보를 한번에 처리하여 성능을 높이자.

인X타그램은 한 번의 API 요청으로 사진, 게시글 텍스트, 태그, 위치 정보 등을 전부 처리하고 싶을 것이다. 이렇게 하지 않으면 각 요청마다 추가적인 트래픽이 발생하고 서버 부하가 늘어날 수 있기 때문이다.

 

어플리케이션 서버에서는 클라이언트에서 전송한 multipart/form-data 형식의 요청을 해석해야 한다.
이를 위해 Spring의 MultipartResolver는 HTTP 요청의 multipart/form-data를 해석하여 파일과 메타데이터를 추출하고 처리한다. 

 
 

MultipartResolver는 껍데기뿐.

서블릿 3.0 이상에서는 Part 객체를 통해 multipart/form-data 형식의 HTTP 요청을 쉽게 처리할 수 있다. 이를 활용하여 클라이언트가 업로드한 파일을 쉽게 다룰 수 있게된다.
Spring에서도 이 기능을 활용하기 위해 MultipartResolver 인터페이스를 제공하고 있다. 이 인터페이스는 'multipart/form-data'를 처리하는 메커니즘을 제공하며, 구현체가 필요하다.


구현체도 잘 골라쓰자.

StandardServletMultipartResolver
vs
CommonsMultipartResolver


CommonsMultipartResolver 이 녀석은 commons-fileupload 라는 라이브러리에 의존하고 있어서 잘 모르고 사용하려다간 에러를 마주할 수 있다.
(과거의 나도 이런 실수를 했다..)

Spring Boot에서는 기본적으로 서블릿 3.0의 Part 객체를 활용하는 StandardServletMultipartResolver를 사용하여 파일 업로드를 처리한다. 따라서 별도의 설정 없이도 'multipart/form-data'를 처리할 수 있다.
 
 

StandardServletMultipartResolver에서 파일 정보를 가져오는 과정

StandardServletMultipartResolver가 파일을 해석하는 과정은 아래와 같다.

  1. DispatcherServlet에서 MultipartResolver 호출:
    • 클라이언트의 HTTP 요청이 들어오면 DispatcherServlet이 MultipartResolver를 호출.
  2. StandardServletMultipartResolver 동작:
    • StandardServletMultipartResolver는 HttpServletRequest가 멀티파트인지 여부를 판단.
    • 멀티파트라면, HttpServletRequest를 StandardMultipartHttpServletRequest로 래핑하여 반환.
  3. StandardMultipartHttpServletRequest 생성:
    • StandardMultipartHttpServletRequest는 HttpServletRequest를 상속받은 클래스로, 멀티파트 파일 업로드와 관련된 정보를 캡슐화.
    • 내부에서는 Part 인터페이스를 사용하여 각 파일에 접근하고 파일의 메타데이터 및 내용을 읽어옴.
  4. StandardMultipartHttpServletRequest에서 파일 정보 추출:
    • StandardMultipartHttpServletRequest를 통해 파일의 메타데이터(파일 이름, 크기 등) 및 내용을 읽어올 수 있음.
    • 클라이언트가 전송한 파일은 Part 객체로 표현되며, getPart(String name) 메서드를 통해 파일의 Part 객체를 가져올 수 있음.

 
 

읽어온 파일 정보를 내가 원하는 객체로 어떻게 바꾸지?

StandardServletMultipartResolver가 멀티파트 요청을 해석하고 Part를 읽어온 다음, @RequestPart 어노테이션이 적용된 파라미터에 맞게 변환된다. 어디서 변환되는 걸까.
Spring MVC 내부의 RequestPartMethodArgumentResolver 클래스는 @RequestPart 어노테이션이 적용된 파라미터를 해석하고, 해당 Part의 내용을 파라미터의 타입에 맞게 변환한다.

 
예를 들어 @RequestPart를 통해 이미지와 JSON 타입의 데이터를 받아온다고 할때, 

@PostMapping("/upload")
        public ResponseEntity<?> upload(@RequestPart(value = "uploadFile", required = false) MultipartFile uploadFile,
                                        @RequestPart(value = "metaData") MetaDataDto metaData) {
            if (uploadFile == null) {
                return new ResponseEntity<>("File is required", HttpStatus.BAD_REQUEST);
            }
            // 파일 처리 로직
            return new ResponseEntity<>("File upload successfully with metadata " + metaData, HttpStatus.OK);
        }

 
MultipartFile에 해당하는 Part는 파일 내용으로 변환되고, MetaDataDto에 해당하는 Part는 JSON 형식의 데이터로 변환한다.
 
 
 
회사에서 파일 업로드 API를 개발하는 도중 발생한 에러를 해결하기 위해 multipart/form-data에 대해 공부했습니다. 데이터 처리 프로세스를 이해하면 문제의 원인을 찾을 수 있기 때문에, 누군가가 제 글을 보고 파일 업로드 요청 처리 프로세스를 이해하는 데 도움을 받길 바라며, 제가 찾아보고 공부한 내용을 공유하고자 합니다.
 
감사합니다.