내용이 안 보인다면 쿠키/캐시를 지우고 새로고침 하세요!
이 블로그는 광고 클릭 수익으로 운영됩니다!
괜찮으시다면 광고 차단을 풀어주세요 ㅠㅠ

게시글

강좌20 - NodeJS - 10달 전 등록 / 4달 전 수정

Access-Control-Allow-Origin(CORS)

CORS, CORB 요청 허용하기
조회수:
0
이 블로그는 광고 클릭 수익으로 운영됩니다!
괜찮으시다면 광고 차단을 풀어주세요 ㅠㅠ
이 블로그는 광고 클릭 수익으로 운영됩니다!
괜찮으시다면 광고 차단을 풀어주세요 ㅠㅠ

안녕하세요. 이번 시간에는 웹 개발자라면 누구나 한 번은 겪는다는 CORS 문제에 대해서 포스팅해보겠습니다. 포스팅 자체는 노드 서버를 기반으로 하지만 노드 서버가 아니더라도 해결할 수 있는 방법을 포스팅 최하단에 적어두었습니다.

클라이언트에서 AJAX 요청을 보내는데 갑자기 다음과 같은 에러가 뜰 때가 있습니다. 같은 요청이더라도 서버에서 서버로 보냈을 때는 되는데 브라우저에서 서버로 보내는 것은 안 되니 당황스러울 것입니다.

undefined

Failed to load https://stackoverflow.com/: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'https://www.zerocho.com' is therefore not allowed access. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

이 에러를 재현해보려면 제 블로그에서 F12로 개발자 도구를 연 후, 다음 코드를 복사해서 콘솔 탭에 붙여넣으시면 됩니다.

var xhr = new XMLHttpRequest();
xhr.onload = function() {
   console.log('xhr loaded');
};
xhr.open('GET', 'https://stackoverflow.com/');
xhr.send();

재밌는 것은 주소를 스택오버플로우 대신 https://zerocho.com으로 바꾸면 잘 동작합니다. 당연한 것이, zerocho.com에서 stackoverflow.com으로 요청을 보내는 것은 도메인이 다르기 때문에 CORS 에러가 뜨는 것이고, zerocho.com에서 zerocho.com으로 보내는 것은 도메인이 같아서 괜찮은 것입니다.

var xhr = new XMLHttpRequest();
xhr.onload = function() {
   console.log('xhr loaded');
};
xhr.open('GET', 'https://www.zerocho.com/');
xhr.send();

이제 콘솔에 xhr loaded가 뜨면서 성공적으로 응답이 왔습니다.

위의 에러는 보안상의 이유로 브라우저들이 다른 도메인에게 XHR 요청을 보내는 것을 제한한 것입니다. 다행히 피해갈 수 있는 방법이 있습니다. 하지만 클라이언트 쪽에서는 힘들고 응답을 받는 서버쪽에서 해결해야 합니다. 클라이언트는 누군지 모르니까 클라이언트의 요청을 함부로 믿을 수 없는 탓이겠지요. 제가 아무리 스택오버플로우에 XHR 요청을 보내려해봐도 스택오버플로우가 저를 CORS 허용 목록에 추가하지 않는 이상 되지 않는 것입니다.

익스프레스에서는 정말 간단하게 해결할 수 있습니다.

npm i cors

cors 패키지를 설치한 뒤, CORS 요청을 허용하고자 하는 익스프레스 라우터에서 다음과 같이 해주면 됩니다.

const cors = require('cors');
const express = require('express');
const router = express.Router();

router.get('/', cors(), (req, res) => { res.send('cors!') });

모든 라우터에 cors()를 적용하고 싶다면 다른 미들웨어들이 있는 부분에 app.use(cors())를 합니다.

단, cors()의 경우에는 모든 요청 오리진을 허용하는 것이기 때문에 위험하니 cors({ origin: 허용 오리진 주소 })처럼 일부 허용할 주소를 넣는 게 좋습니다. cors({ origin: 'https://www.zerocho.com' }) 이런 식으로요.

익스프레스를 쓰지 않더라도, 서버가 노드가 아니더라도 기본적인 원리는 간단합니다. 요청 응답 헤더에 Access-Control-Allow-Origin: '*'을 넣어주면 됩니다. '*'은 모든 요청 오리진을 허용하는 것이기 때문에 위험하니 이 부분만 허용하는 오리진으로 바꿔주면 되겠죠.

노드의 경우는 res.writeHead(200, { 'Access-Control-Allow-Origin': '*' }); 이렇게 하면 됩니다. 다른 서버도 응답 헤더를 다음과 같이 바꿔줍시다.

크롬 등의 브라우저는 localhost에서는 CORS 요청이 안 되도록 막아두기도 하여 저렇게 허용을 해줘도 안 될 수도 있습니다. localhost의 경우에는 안 돼도 너무 당황하지 맙시다.

또한 CORS 외에도 CORB(cross origin read blocking) 현상도 있습니다. CORS를 허용했더라도 POST, PUT, DELETE 요청에서 json을 전송하는 경우 요청이 차단됩니다. 이럴 때는 json 대신 www-form-urlencoded 형식으로 데이터를 보내면 됩니다.

Access-Control-Allow-Origin 외에도 관련 헤더들이 많은데 모질라 에 잘 설명되어 있습니다.

투표로 게시글에 관해 피드백을 해주시면 많은 도움이 됩니다. 오류가 있다면 어떤 부분에 오류가 있는지도 알려주세요! 잘못된 정보가 퍼져나가지 않도록 도와주세요.
Copyright © 2016- 무단 전재 및 재배포 금지

댓글

4개의 댓글이 있습니다.
4달 전
localhost에서 안될수도잇다는데 로컬개발시 잘되는지 확인방법이 있을까요 ?
4달 전
안 되는 경우 콘솔에 위 그림과 같은 에러가 뜹니다. 된다면 네트워크 탭에서 성공적으로 응답을 받아오는 것을 확인하실 수 있습니다.
4달 전
what should I do in java server??
4달 전
Every server runs in the same way. Just add Access-Control-Allow-Origin: '*' to your response header. As far as I know, there's res.setResponseHeader or something like that in Java.
4달 전
express에서는 굉장히 쉽게 해결할수 있네요. 감사합니다
5달 전
좋은 정보 감사합니다 덕분에 해결했네요 ㅠㅠ