CORS, 근데 이제 413 에러를 곁들인...

rudwnd33·2021년 12월 17일
26

TIL

목록 보기
67/77
post-thumbnail

구글에 검색했을 때 한글로 된 명확한 해결 방법이 나오지 않는 것 같아서 작성해보았습니다. 😎

EB로 배포한 프로젝트에 이미지 파일을 업로드 할 때 아래와 같은 에러가 뜨는 경우가 있었다.
내가 이미지 업로드 했을 때는 분명 정상적으로 되는데 다른 분이 업로드 했을 때는 정상적으로 되지 않았다.
그래서 컴퓨터 환경마다 다른가? 생각했는데 혹시나 해서 용량이 큰 이미지를 업로드 해봤다. 업로드가 안 된다... 다른 분이 용량이 큰 이미지를 업로드 하려고 하셨나 보다.

아래와 같은 에러가 웹 브라우저 콘솔에 떴다.

POST https://api.~~~net::ERR_FAILED 413

Access to XMLHttpRequest at 'https://api.~~~' from origin 'https://www.~~~' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

HTTP 413 상태 코드(Payload Too Large)는 요청 엔티티가 서버에 의해 정의된 제한보다 크다는 것을 나타낸다.

CORS 에러가 뜨는 것은 응답 헤더에 Access-Control-Allow-Origin 부분이 없기 때문에 요청을 보내는 클라이언트에게 이를 볼 수 있는 권한이 없다는 것이다. ??? 난 분명 스프링 시큐리티에서 CORS 설정을 했는데 왜 CORS 에러가 뜨지??

Nginx 사용 시 4xx 또는 5xx 오류에 대해 서버는 Access-Control-Allow-Origin를 응답 헤더에 추가하지 않는다. 서버는 2xx3xx(redirection)에 대해서만 해당 헤더를 보낸다.

만약 4xx 또는 5xx 오류에 대해서도 Access-Control-Allow-Origin를 응답 헤더에 추가하고 싶다면 Nginx에서 아래와 같이 추가하면 된다.

add_header <header_name> <value> always
# 예시
add_header 'Access-Control-Allow-Origin' '*' always

참고
https://stackoverflow.com/questions/60537280/why-browsers-display-cors-error-in-case-of-response-413

따로 설정한 거 아니면 4xx, 5xx 에러에 대한 CORS 에러는 뜨는 거니까, 그럼 413 에러를 해결하면 자동으로 CORS 문제가 해결이 된다는 말씀!! 413 에러를 해결해보자.

  • CORS 설정을 했는데도 CORS 문제가 413 에러 뿐만 아니라 4xx, 5xx 에러와 같이 발생한다면 당황하지 말 것!

우선 Nginx에서 기본적으로 요청 엔티티의 크기는 1MB로 제한이 되어 있다. 그래서 1MB가 넘는 이미지를 업로드 했을 때 413 에러가 발생했던 것이다.

왜 1MB로 제한을 했을까??

EB를 이용해서 웹 서비스를 Deploy 할 경우 어플리케이션의 Reverse Proxy로 사용되는 Nginx의 설정 때문이다. Nginx의 설정 값 중 client_max_body_size를 이용하면 client가 너무 큰 사이즈의 request를 보내지 못 하도록 제한을 걸 수 있다. 이 설정은 requestContent-Length 헤더값이 client_max_body_size에 설정된 값을 넘을 수 없도록 제한한다.
악의적인 대용량 파일 업로드 등을 방지하는데 사용한다.

참고
https://blog.choyoungil.com/2021/08/06/aws-elastic-beanstalk-413-request-entity-too-large-%EC%98%A4%EB%A5%98-%ED%95%B4%EA%B2%B0/

그럼 어떻게 Nginx의 업로드 크기 제한을 수정할 수 있을까?

파일 업로드 사이즈를 설정하기 위해서는 먼저 nginx의 설정파일을 수정해야 한다. nginx.conf 파일은 아래의 경로에 있다. 읽기 전용이므로 root 계정이 필요하다.

$ vim /etc/nginx/nginx.conf

설정된 부분으로 이동한 후 http { } 안에 해당 속성과 값을 추가하거나 변경해야 한다. 이때 client_max_body_size 속성과 값을 설정해야 한다. 만약 50MB까지 허용하는 경우라면 아래처럼 설정한다.

http {
  client_max_body_size 50M;
  ...
}

업로드 크기에 대해 수정이 되었으면

# nginx 재시작
nginx -s reload

또는

# service 재시작
service nginx restart

하면 된다.

참고
https://webisfree.com/2018-03-29/nginx-413-request-entity-too-large-%EC%97%90%EB%9F%AC-%ED%95%B4%EA%B2%B0%ED%95%98%EA%B8%B0-%ED%8C%8C%EC%9D%BC-%EC%97%85%EB%A1%9C%EB%93%9C-%EC%82%AC%EC%9D%B4%EC%A6%88

위에서 설명한 부분은 Nginx에 대해 직접 설정할 때 사용하면 될 것 같은데, 내가 적용하려고 하는 건 AWS EBDocker 환경으로 배포되고 있는 프로젝트다.

EB를 통해 생성된 EC2에 SSH로 접속해서 Nginx에 대한 파일을 찾아 위 방법대로 설정하면 할 수는 있겠지만 만약에 AutoScaling으로 EC2가 추가로 생성된다면 또 해당 EC2에 접속해 또 설정해야 할 것이다.

나는 GitHub ActionsEB무중단 배포를 하고 있는데... 어떻게 해야 하지??

https://stackoverflow.com/questions/18908426/increasing-client-max-body-size-in-nginx-conf-on-aws-elastic-beanstalk 에 의하면

Amazon Linux2 이전에는

|-- .ebextensions
|   `-- nginx
|       `-- conf.d
|           `-- myconf.conf
`-- 프로젝트 파일들

위 구조로 .conf 파일에 Nginx 관련 설정을 추가하면 된다고 한다.

하지만 내가 적용하는 프로젝트는 Amazon Linux2다. .ebextensions 대신 .platform을 사용한다고 한다.

|-- .platform
|   `-- nginx
|       `-- conf.d
|           `-- myconf.conf
`-- 프로젝트 파일들

.conf 파일의 내용은 아래와 같다.

# nginx의 기본 업로드 제한 1MB
# 제한 풀기 -> 0
client_max_body_size 0;

0을 넣으면 제한을 풀 수 있고 원하는 크기(예를 들면 50MB -> 50M)를 지정할 수도 있다.

어떤 답변을 보면

|-- .platform
|   `-- nginx
|       `-- conf.d
|           `-- myconf.conf
|   `-- 00_myconf.config
`-- 프로젝트 파일들

00_myconf.config 파일이 .platform 바로 아래 위치에 넣는 게 추가 되었는데

이 파일의 내용은 아래와 같다.

container_commands:
  01_reload_nginx:
    command: "service nginx reload"

Nginx 서비스를 다시 재시작하는 것이다.

근데 EBdeploy 할 때 Nginx를 다시 시작하기 때문에 .config 파일은 필요 없을 것 같다고 한다.

|-- .platform
|   `-- nginx
|       `-- conf.d
|           `-- myconf.conf
`-- 프로젝트 파일들

이 방법으로 하고 GitHub Actions를 돌려서 초록불이 들어왔다! 설렘 반 기대 반

구축한 웹 사이트에 들어가 1MB가 넘는 이미지를 업로드 했더니!! 뭐야 똑같네 안 되네...
허무했지만 하나의 댓글이 눈에 띄었다.

맞아 나 도커 환경 EB였지... 그럼 Dockerrun.aws.json 파일과 관련이 있을 거야...

GitHub Actions로 배포하기 전에 테스트로 EB Console로 직접 업로드 해봐야지..!

클릭!

파일 선택을 누르기 앞서

Dockerrun.aws.json 파일과 .platform/nginx/conf.d/myconf.conf 파일을 zip으로 압축한다.

압축한 zip 파일을 위 사진의 파일 선택 버튼을 통해 선택한다!

그리고 배포를 똿! 누르면

고래 왼쪽으로 상태가 빙글빙글 돈다. 과연... 될까???

✅ 초록!

그럼 이제 웹 사이트로 가서 업로드가 잘 되는지 보자

너무 잘 올라가고,,,

감사합니다... 구박사님, 스택 오버플로우 박사님들,,,

그럼 이제 진짜 진짜 마지막으로 GitHub Actions에서 배포했을 때 자동으로 적용되게 수정을 해야겠지!

.github/workflows/deploy.yml로 가보자

- name: Generate deployment package
    run: |
      mkdir -p deploy
      cp Dockerrun.aws.json deploy/Dockerrun.aws.json
      cd deploy && zip -r deploy.zip .

이 부분만 손 보면 된다.

기존에는 deploy 디렉토리를 만들어 Dockerrun.aws.json 파일을 deploy 디렉토리 안으로 복사하고 해당 디렉토리로 들어가 zip으로 압축했다.

근데 이제는 .platform/nginx/conf.d/myconf.conf 파일도 같이 압축해야 하기 때문에

- name: Generate deployment package
    run: |
      mkdir -p deploy/.platform/nginx/conf.d
      cp Dockerrun.aws.json deploy/Dockerrun.aws.json
      cp .platform/nginx/conf.d/proxy.conf deploy/.platform/nginx/conf.d/proxy.conf
      cd deploy && zip -r deploy.zip .

위와 같이 수정했다.

수정하고 deploy 브랜치push 하니까 GitHub Actions가 노란색으로 빙빙 돈다.

✅ 초록불이다 ㅎㅎ

웹 사이트로 들어가서 이미지를 업로드 해보니 아주 잘 올라간다!
하지만 파일의 용량이 크다 보니 속도가 느려진 느낌이 든다.
이 부분에 대해서는 부하 테스트를 진행해보고 개선해보는 방향으로 나아가야 할 것 같다.

오늘의 삽질 끝!

profile
주니어 백엔드 개발자

4개의 댓글

comment-user-thumbnail
2021년 12월 18일

넘넘 유익해요!

1개의 답글
comment-user-thumbnail
2021년 12월 23일

저희도 413에러로 고생하고있었는데 감사해욤 👍🏻

1개의 답글