팀 프로젝트 진행 당시 백엔드 서버가 추천서버(FastAPI)와 그 외의 서버(Spring Boot)로 나누었다. 머신러닝을 통해 협업 필터링 기반 추천 알고리즘을 구현하는 팀원이 파이썬이 주력 언어라 FastAPI로 서버를 구현했다.
나는 이걸 Docker Image로 만들어서 Container로 EC2에 배포했는데 당시에 겪었던 문제(파이썬 버전에러, 리눅스와 윈도우의 의존성이 다른문제:pywin 등등)중에 하나인 POST로 요청을 보내면 리다이렉션후 POST메소드가 GET이 되어버리는 문제에 대해 써보고자한다.
아키텍처
우선 요청이 어떤 흐름으로 가는지 추천서버 위주로 그림을 통해 살펴보자.
우선 요청이 오면 Nginx
가 URL을 보고 요청을 어디로 보낼지 판단해주는 리버스 프록시 역할을 했다.
그래서 추천 서버에 유저의 선호데이터를 보내는 API를 호출했을 때(service-name/prefer
) 이를 추천서버로 리다이렉트 하는 흐름으로 Nginx 설정 파일을 짰다.
아래는 Nginx설정 파일 중 일부다.
#...
upstream fastapi{
server #deleted:5000;
}
#...
server{
listen 80;
server_name #deleted;
location / {
#후에 문제가 되는부분
return 301 https://$host$request_uri;
}
location /.well-known/acme-challenge/ {
allow all;
root /var/www/certbot;
}
}
server {
#...
### 리버스프록시를 통해 각 요청을 backend, frontend로 보내는 코드는
## 글과 관련이 없어서 지웠다.
location /fastapi {
proxy_pass http://fastapi;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
#...
}
참고로 프로젝트에서 추천은 세계 여러나라의 과자를 추천해주는 기능이였다.
문제
문제는 Postman으로 POST
요청을 통해 유저의 선호도 조사 결과를 보낼 때 나타났다.
추천서버에 요청이 GET
으로 도달했다. 당시에는 몰랐는데 이제보니 HTTP버전도 1.0으로 갔다 .. ㅋㅋㅋㅋ(이건 postman으로 요청을 보낼 때 앞에 http://
를 생략해버려서 나타난 문제였다.)
INFO: 172.22.0.1:36286 - "GET /prefer HTTP/1.0" 405 Method Not Allowed
어쨌든 GET /prefer
를 처리하는 API는 없었기에 405에러가 나타났다.
위의 nginx설정에서 볼 수 있듯이 Web 서버는 301 Moved Permanently
를 반환했고, POSTMAN이 301
에 따라 리다이렉트 하면서 GET
으로 바꿔서 요청을 다시 보내는 것이 원인이다.
난 분명 POST요청을 보냈는데 GET요청이 되어버리는 문제를 찾아보니 이런 자료가 나왔다.
postman support에 있는 나와 같은 문제
해당 링크를 보면 아래같은 구문이 있다.
This is mostly due to a server-side redirect. If Postman receives a 301 or 302 response code, it will automatically follow the redirect. Similar to the behaviour in browsers, the original request method will NOT be preserved, and the redirected request will be made with a GET method.
해결
당시에 http에 대한 지식이 부족했기에 301 Redirection이 어떤 원리인지 다른 3xx코드는 무엇인지 정확히 알지 못했기 때문에 이런 문제가 났다.
첫 번째 방법
- 요청을 리다이렉션 하는 부분에서 301 -> 308로 바꿔준다.
리다이렉션에 대해 좀 더 자세히 알아보자.
링크에서 눈여겨 볼 부분은 아래 표이다.
코드 | 텍스트 | 메서드 핸들링 | 일반적인 유스케이스 |
301 | Moved Permanently | GET 메서드는 변경되지 않습니다. 다른 메서드들은 GET 로 변하거나 변하지 않을수도 있습니다.[1] | 웹 사이트의 재편성. |
308 | Permanent Redirect | 메서드와 본문은 변하지 않습니다. | GET이 아닌 링크/동작을 지닌, 웹 사이트의 재편성. |
두 번째 방법
Postman에서 요청을 보낼 때
http://
로 보내지말고https://
로 보낸다. 이렇게 하면 http(80포트)로 오는 요청을 https(443)로 리다이렉트하지 않기 때문에 원래의 메서드가 유지된다.(위에 있는nginx의 설정 참고)-
또한 Postman에서
Follow original HTTP Method
라는 설정도 있는데 이 설정이 꺼져있다면 308 리다이렉션을 해도GET
으로 메서드가 변경되버릴지도 모른다
마치며
http프로토콜과 Response code에 대해서 잘 몰랐기 때문에 문제를 파악하는데 시간이 걸렸던 문제다. 이번김에 3xx번대 코드에 대해서 잘 알게 됐다.