[HTTP/Server] CORS 에러 해결하기 (헤더 설정, Proxy 사용)

초코침·2023년 6월 7일
0

CORS 헤더 설정을 따로 하지 않은 서버에 다른 출처에서 요청을 보내는 경우 다음과 같이 CORS 에러가 표시된다.

이는 동일 출처 정책(SOP)에 의해 차단되는 다른 출처에서의 요청을 허용하기 위해서는 CORS 정책의 Access-Control-Allow-Origin 헤더에 요청을 보내려는 출처가 명시돼 있어야 하는데 명시돼 있지 않아 나타나는 에러 메시지다.

따라서 위 에러를 해결하려면 CORS 헤더를 설정해 주어야 한다.

CORS 헤더 설정해 에러 해결하기 (Express 서버)

여기서 사용하는 서버는 express 서버라서 cors 라이브러리를 설치해 헤더를 적용할 것이다.

  1. 라이브러리를 설치
npm install cors
  1. cors 헤더를 적용
const cors = require('cors');

app.use(
  cors({
    'Access-Control-Allow-Origin': '*', // 모든 출처로부터 요청 허용
    'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
    'Access-Control-Allow-Headers': 'Content-Type, Accept',
    'Access-Control-Max-Age': 10,
  })
);

이렇게 헤더를 적용해 주면, 더 이상 cors 에러 메시지가 발생하지 않는다.

proxy로 에러 해결하기

cors 헤더를 설정하는 것은 서버 쪽에서 해야 하는데, 클라이언트에서 프록시 기능을 사용해 이를 해결할 수도 있다.

proxy

proxy란 클라이언트에서 서버로 접속할 때 클라이언트가 직접 접속하지 않고 대리로 접속할 수 있게 중계자로써 기능하는 것을 말한다.

서버로 요청을 보내고 응답을 받는 기본적인 흐름은 다음과 같다.

  1. app에서 브라우저로 요청 전송
  2. 브라우저가 서버로 리소스 요청
  3. 서버는 접근 권한(요청을 보낸 출처가 우리 서버에 요청을 보낼 수 있는 유효한 출처인지)을 확인하여 브라우저에게 응답 전송
  4. 서버로부터 응답을 받은 브라우저는 응답에 따라 app에게 리소스를 전달(통신 가능)해 주거나, cors 에러(통신 불가)를 발생시킴 (preflight 요청을 보내는 경우, OK 응답이라면 리소스 요청을 한 번 더 보낸 다음에 온 응답을 app에게 전달)

즉, 요청을 보내는 출처가 서버에서 허용한 출처인지 검사하고 통과되어야만 서버로부터 리소스를 획득할 수 있다.

여기서 proxy를 적용하면 흐름은 다음과 같이 바뀐다.

  1. app에서 브라우저로 요청 전송

/ 수정 필요 /

1. react-script로 프록시 설정하기 (webpack dev server proxy)

CRA로 만든 React 앱의 package.json을 열어 요청하려는 주소를 proxy로 적어준다.

(...)
	"browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  },
  "proxy": "http://localhost:3080"	
}

그리고 코드에서 요청을 보내려는 URL에서 proxy로 작성한 부분을 지워준다. (요청하는 도메인이 생략된 경우 현재 페이지의 도메인(ex. http://localhost:3000)을 가리키게 됨)

export const getAllBooks = async () => {
	// const response = await fetch('http://localhost:3080/api/books');
  const response = await fetch('/api/books');
  return await response.json();
};

코드를 작성하고 요청을 보낸 다음 네트워크 탭에서 보낸 요청을 확인해 보면, http://localhost:3080/api/books가 아닌 http://localhost:3000/api/books에 요청을 보냈음을 알 수 있다. (포트번호 차이)

결론적으로 http://localhost:3000이라는 출처에서 동일한 출처로 요청을 보냈기 때문에 CORS 에러가 발생하지 않는다.

1-2. 여러 도메인에 요청을 보내야하는 경우

서버가 여러 개인 경우, proxy를 객체로 작성하면 된다.

(...)
	"browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  },
	"proxy": {
		"/api1/": {
			"target": "http://localhost:1000"
		},
		"/api2/": {
			"target": "http://localhost:2000"
		},
		"/auth/": {
			"target": "http://localhost:4000"
		},
	}
}

2. http-proxy-middleware 라이브러리 사용하기

라이브러리를 설치한다.

npm install http-proxy-middleware

프록시를 셋팅하기 위해 setupProxy.js 파일을 src 폴더에 생성하고 다음과 같이 작성한다.

app.use를 호출해 여러 개의 도메인을 작성할 수 있다.

const { createProxyMiddleware } = require('http-proxy-middleware');

module.exports = function (app) {
	app.use(
    '/api',
    createProxyMiddleware({
      target: 'http://localhost:3080',
      changeOrigin: true,
    })
  );
  app.use(
    '/api2',
    createProxyMiddleware({
      target: 'http://localhost:3070',
      changeOrigin: true,
    })
  );
};
  • target: 엔드포인트를 제외한 출처(프로토콜, 호스트, 포트번호)
  • changeOrigin: 호스트 헤더의 출처를 target으로 변경할지 여부 (cors 통과 위해 true로 바꿔줌)
profile
블로그 이사중 🚚 (https://sungjihyun.vercel.app)

0개의 댓글