문제상황
- 공지사항 게시판을 구현하면서, 본문에 들어갈 이미지를 업로드할 수 있는 API를 구현하던 상황
- 특정 용량이 넘는 이미지를 업로드하려고 하면 nginx에서 413 Request Entity Too Large 에러가 발생했습니다.
- 클라이언트(브라우저)의 개발자 도구에선 CORS Error로 보여졌습니다.
원인
저희는 Reverse proxy로 nginx를 사용하고 있었는데, 기본적으로 파일 업로드 크기가 1MB로 제한되어 있더라구요. 그래서 이 설정을 수정해야만 합니다.
Forward proxy?
- 일반적인 프록시를 말하며, 다수 클라이언트의 요청을 받아 미들웨어처럼 목적지에 대신 요청을 보내서 받은 응답을 클라이언트에 전달(forward)해준다.
- 캐싱 기능을 통한 성능 향상, 특정 도메인만 사용 가능하도록 웹 환경 제한, 오리진의 익명성 강화 등
Reverse proxy?
- 클라이언트가 아닌 서버를 위한 프록시
- 클라이언트 측의 요청을 받아 서버에게 전달한 뒤, 다시 클라이언트에게 결과를 응답한다.
- 로드 밸런싱, 보안 강화, 캐싱, SSL 암호화 등
즉, 클라이언트와 서버 간의 통신은 클라이언트 ↔ 포워드 프록시 ↔ 리버스 프록시 ↔ 서버로 이루어진다고 할 수 있습니다.
해결
파일 업로드 크기 제한을 늘리기 위해 nginx 설정 파일을 수정합시다. 저희는 AWS Elastic Beanstalk를 사용해서 어플리케이션을 배포하기 때문에 프로젝트 루트의 .ebextensions/nginx 디렉토리의 파일들을 수정해야 합니다.
- eb로 배포한 인스턴스의 nginx 설정은 /etc/nginx/nginx.conf 에서 확인할 수 있습니다.
- .ebextensions/nginx/conf.d/*.conf : 해당 위치의 설정 파일들은 nginx 설정의 http 블록에 위치합니다.
- .ebextensions/nginx/conf.d/elasticbeanstalk/*.conf : 해당 위치의 설정 파일들은 nginx 설정의 http.server 블록에 위치합니다.
저는 그래서 04_max_body_size.conf 라는 파일을 만들어 파일 업로드 제한을 5MB로 증가시켰습니다.
아래 파일을 읽어 nginx.conf의 http.server 블록에 해당 설정이 추가됩니다.
// .ebextensions/nginx/conf.d/elasticbeanstalk/04_max_body_size.conf
client_max_body_size 5M;
구글링해보니 이를 http 블록 또는 server 블록에 넣는지 다 제각각이었는데, 어느 곳에 넣어도 의도대로 동작하였습니다.
다시, 문제 발생
그런데 5MB 이미지 업로드에 실패했습니다. 저는 MultipartFile을 이용해서 이미지 업로드 API를 구현했는데, 이와 관련해서 예외가 발생했습니다. 업로드 크기 제한을 초과했다는 내용이었습니다.
multipart.MaxUploadSizeExceededException:
Maximum upload size exceeded; nested exception is java.lang.IllegalStateException:
org.apache.tomcat.util.http.fileupload.FileUploadBase$FileSizeLimitExceededException:
The field sourceFile exceeds its maximum permitted size of 1048576 bytes.
MultipartFile?
- 스프링에서 제공하는 인터페이스
- multipart request로 받은 파일을 표현
- multipart는 http 통신에서 multipart/fomr-data라는 Content-Type으로, http message body 부분에 boundary 기준으로 여러 데이터를 한 번 요청으로 보내는 것
원인과 해결
nginx처럼 스프링에서 제공하는 mutlipartfile에는 기본 제한이 걸려있었습니다. 이를 다음 설정으로 수정해주면 됩니다. (스프링 부트 2.0 이상에 해당하는 설정이고, 그 이전 버전은 조금씩 다르다고 하니 추가 문서를 참고하세요)
// application.yml
spring:
servlet:
multipart:
max-file-size: 5MB
max-request-size: 5MB
max-file-size는 요청에 담을 수 있는 한 파일의 최대 크기(multipart에서 boundary로 구분되는 특정 영역), max-request-size는 총 요청 크기(multipart 총 크기)를 의미합니다. 아무것도 설정하지 않았을 때 기본적으로 전자는 1MB, 후자는 10MB라고 합니다. 저는 어차피 1개 요청에 1개의 이미지 파일만을 업로드할 수 있는 구조라 똑같이 5MB로 제한했습니다.
이렇게 크기 제한을 늘리고 원하는 대로 본문 이미지를 업로드할 수 있게 되었습니다. 해결! 🤗
추가학습
AWS Elastic Beanstalk는 nginx를 default reverse proxy로 사용하여 어플리케이션을 Elastic Load Balancer에 매핑하는데, 이 때 nginx 구성을 어떻게 변경할 수 있는지 "역방향 프록시 구성" 탭에서 확인할 수 있습니다. 이 외에도 플랫폼 확장, 리버스 프록시 교체, 어플리케이션 빌드 및 명령 스크립트 등에 대한 정보를 제공합니다.
스프링 부트 버전별 파일 크기 제한 설정, max-file-size와 max-request-size를 설명한 글입니다.
'문제해결' 카테고리의 다른 글
Testcontainers - Localstack 설정 중 생겼던 궁금증 (0) | 2021.04.25 |
---|---|
Mock 테스트에서 Spring 프로퍼티를 읽어올 수 없던 문제 (0) | 2021.04.11 |
댓글