해결된 질문
작성
·
2.3K
·
수정됨
0
안녕하세요 제로초님~!
최근에 socket.io 문제를 해결해주셔서 감사합니다. 제로초님 덕분에 몇주간 있었던 불면증이 사라졌습니다.
이번에 드리고자 하는 질문은 백엔드 api 서버와 리액트 로컬호스트의 websocket 연결에서 cors 에러가 사라지지 않고 있다는 것입니다.
프론트와 백엔드 둘다 localhost로 사용했을땐 문제 없이 잘 작동하였으나, 백엔드 api 서버와 프론트(리액트) http://localhost:3000 로 연결하려 하니 cors 에러가 사라지질 않네요.
백엔드 api 서버주소는 https://api.yubinhome.com/ 이고, traefik 을 사용해 https 인증을 받고 있습니다.
제가 어떤 부분을 놓친 것인지 함께 봐주실 수 있을까요?
Access to XMLHttpRequest at 'http://api.yubinhome.com/socket.io/?EIO=4&transport=polling&t=Ohzm2CT' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: Redirect is not allowed for a preflight request.
GET http://api.yubinhome.com/socket.io/?EIO=4&transport=polling&t=OhzmhTk net::ERR_FAILED
1. 공식 문서에 나온대로 api url 에 직접 연결해보니 서버가 작동하고 있는 것은 확실해보입니다.
소켓io 공식문서 cors : https://socket.io/docs/v3/handling-cors/#troubleshooting
2. 서버측 origin, credetials 를 설정하였습니다. origin : "*" 가 문제인가 싶어 http://localhost:3000 url 을 직접 주었습니다.
클라이언트 측에는 withCredentials: true 을 설정해주었습니다.
백엔드 api 서버 코드
https://github.com/fog-of-war/dev-be/blob/dev/src/events/events.gateway.ts
@WebSocketGateway({
cors: {
origin: "http://localhost:3000",
methods: ["GET", "POST"],
allowedHeaders: ["authorization", "Authorization"],
credentials: true,
},
namespace: /\/ws-.+/,
transports: ["websocket", "polling"],
})
REACT_APP_API_URL=https://api.yubinhome.com/
REACT_APP_SOCKET_URL=ws://api.yubinhome.com/v1/ws-alert
let socket: any = null;
socket = io(socketUrl + "-" + userId, {
withCredentials: true,
extraHeaders: {
Authorization: `Bearer ${sanitizedToken}`,
},
});
답변 2
0
헤더를 보여주실 때 빨간 요청/응답의 헤더를 보여주셔야죠.
Response to preflight request doesn't pass access control check: Redirect is not allowed for a preflight request.
이 메시지가 에러의 핵심입니다. Redirect가 일어나서 그렇습니다. 307 internal redirect가 왜 일어나나요?? nginx 같은 거 쓰시나요?
넵넵 트래픽(traefik) 사용합니다!
딱 봐도 아시는군요! 멋지십니다.
빨간색에는 응답헤더가 없는 상태입니다.
docker-compose로 트래픽 설정을 해둔상태입니다.
version: "3.8"
services:
web:
image: shinyubin/fow-be
container_name: fow-be
restart: always
labels:
- "com.centurylinklabs.watchtower.enable=true"
- "traefik.enable=true"
- "traefik.http.routers.web.rule=Host(`api.yubinhome.com`)"
- "traefik.http.routers.web.entrypoints=websecure"
- "traefik.http.routers.web.tls.certresolver=myresolver"
ports:
- "5000:5000"
volumes:
- .:/usr/src/app
- /usr/src/app/node_modules
command: sh -c "npx prisma migrate dev && npm run start:dev"
environment:
- DATABASE_URL={DATABASE_URL}
- JWT_SECRET={JWT_SECRET}
- GOOGLE_OAUTH_ID={GOOGLE_OAUTH_ID}
- GOOGLE_OAUTH_SECRET={GOOGLE_OAUTH_SECRET}
- KAKAO_CLIENT_ID={KAKAO_CLIENT_ID}
- NAVER_CLIENT_ID={NAVER_CLIENT_ID}
- NAVER_CLIENT_PW={NAVER_CLIENT_PW}
- GOOGLE_REDIRECT_URL={GOOGLE_REDIRECT_URL}
- KAKAO_REDIRECT_URL={KAKAO_REDIRECT_URL}
- NAVER_REDIRECT_URL={NAVER_REDIRECT_URL}
networks:
- freecodecamp
depends_on:
- dev-db
dev-db:
image: postgres:13
ports:
- 5432:5432
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: 123
POSTGRES_DB: nest
networks:
- freecodecamp
traefik:
image: "traefik:v2.0"
command:
- "--api.insecure=false"
- "--providers.docker=true"
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
- "--certificatesresolvers.myresolver.acme.httpchallenge=true"
- "--certificatesresolvers.myresolver.acme.httpchallenge.entrypoint=web"
- "--certificatesresolvers.myresolver.acme.email=fogofseoul@gmail.com"
- "--certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json"
ports:
- "80:80"
- "443:443"
volumes:
- "./letsencrypt:/letsencrypt"
- "/var/run/docker.sock:/var/run/docker.sock"
networks:
- freecodecamp
watchtower:
image: containrrr/watchtower
volumes:
- /var/run/docker.sock:/var/run/docker.sock
environment:
TZ: Asia/Seoul
WATCHTOWER_CLEANUP: "true"
WATCHTOWER_POLL_INTERVAL: 60
restart: unless-stopped
networks:
freecodecamp:
https://nhj12311.tistory.com/624
웹서버에서 hsts 관련 옵션 끄면 된다고 합니다. traefik에서도 이 옵션 끌 수 있나 찾아보세요.
web:
image: shinyubin/fow-be:latest
container_name: fow-be
restart: always
labels:
- "com.centurylinklabs.watchtower.enable=true"
- "traefik.enable=true"
- "traefik.http.routers.web.rule=Host(`api.yubinhome.com`)"
- "traefik.http.routers.web.entrypoints=websecure"
- "traefik.http.routers.web.tls.certresolver=myresolver"
# HSTS 비활성화
- "traefik.http.middlewares.hsts.headers.stsPreload=false"
공식문서 sts preload 설정
https://doc.traefik.io/traefik/middlewares/http/headers/#stspreload
hsts 비활성화를 공식문서에서 찾아 추가해보았으나 동일한 에러가 발생하네요.
검색을 통해 이해한 바로는 hsts 를 활성화하면 http 로 오는 요청도 https로 강제로 바꿔주는것으로 보입니다. 그렇다면 ws 프로토콜로 오는 요청도 https 로 강제로 바꿔버릴 수 있어 잘 작동하지 않을수 있기 때문에 제로초님께서 sts preload 옵션을 끄는 것으로 요청하신 것으로 이해가 되네요. 제가 이해한 바가 맞을까요?
추가로 공식문서에 CORS 미들웨어 설정 내용을 찾아 제 docker-compose.yml에 라벨을 추가해보니 oauth 로그인이 불가해진것을 확인하고 주석 처리했습니다.
# CORS 미들웨어 설정
# - "traefik.http.middlewares.cors.headers.accesscontrolallowmethods=*"
# - "traefik.http.middlewares.cors.headers.accesscontrolalloworiginlist=*"
# - "traefik.http.middlewares.cors.headers.accesscontrolmaxage=100"
# - "traefik.http.middlewares.cors.headers.addvaryheader=true"
지금 보시면 http 요청을 보낼 때 https로 강제로 바뀌고 있습니다. 여기서 cors가 발생하는 것이고요. http -> https로 바뀌는 동작을 막아야합니다. 아니면 transport가 현재 polling인데 이걸 websocket으로 설정하시면 http 요청을 처음부터 보내지 않을 겁니다.
현업에서는 로컬호스트에서 cors가 일어날 일이 없습니다. 로컬호스트는 개발 서버를 바라보고 개발 서버에는 cors 허용이 되어있어서 에러가 발생하지 않습니다.