CORS_이슈_해결하기 - boostcamp-2020/IssueTracker-28 GitHub Wiki

1. CORS(Cross-Origin Resource Sharing)란?

CORS란 추가 HTTP 헤더를 사용하여 브라우저가 실행 중인 웹 애플리케이션에 선택된 액세스 권한을 부여하도록 하는 메커니즘.
다른 출처(도메인, 프로토콜 또는 포트)의 자원 및 리소스를 요청할 때 cross-origin HTTP 요청을 실행한다.
.

  • 서버의 기본 설정에서 CORS_ORIGIN_ALLOW_ALL를 활성화했을 경우 CORS의 요청을 허용하여 응답한다.
  • 브라우저에서는 언제든지 CORS를 허용을 할 수 있다. 브라우저의 옵션(크롬의 경우 chrome://flags/), CORS 확장프로그램은
    해당 옵션을 수정 및 요청 시 헤더에 "Access-Control-Allow-Origin"을 추가하는 역할을 한다.

2. CORS 에러 해결방법

CORS 에러는 보안상의 이유로 브라우저들이 다른 도메인에게 XHR 요청을 보내는 것을 제한한 것.
클라이언트는 누군지 모르니까 클라이언트의 요청을 함부로 믿을 수 없어 생기는 문제로,
아무리 스택오버플로우에 XHR 요청을 보내려해봐도 스택오버플로우가 CORS 허용 목록에 클라이언트를 추가하지 않는 이상 되지 않는 것.
이러한 CORS의 해결방법 세 가지를 아래에 정리하여 보았다.

1) CORS 미들웨어 (서버)

이러한 문제는 다행히 응답을 받는 서버쪽에서 간단히 해결할 수 있다.(프론트에서도 해결가능. 2),3)참고)
익스프레스에서는 이를 정말 간단하게 해결할 수 있다.

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' })

2) Proxy 설정 (프론트)

1.클라이언트 단에서 http-proxy-middleware를 설치한다.

npm install http-proxy-middleware - -save

​ 2. src/setupProxy.js 생성후 코드를 다음과 같이 작성한다.

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

module.exports = function(app) {
  app.use(
    '/api',
    createProxyMiddleware({
      target: 'http://localhost:5000',
      changeOrigin: true,
    })
  );
};

target에는 서버 주소나, 서버에서 사용할 포트를 적어준다. (위의 경우는 5000번 포트) 이와 같이 작성할 경우, /api로 시작하는 요청에 대해 프록시 처리를 해주기 때문에 CORS 이슈를 해결할 수 있다.

​이제 아래와 같이 요청을 확인하고, 실행한 뒤의 결과를 확인해보자.
(서버)

(클라이언트)

(결과)

정상적으로 요청을 처리하는 것을 볼 수 있다!

3) Webpack설정 / package.json 설정 (프론트)

package.json으로 설정하는 경우
.
웹팩 개발서버의 proxy 설정은 원래 웹팩 설정을 통해서 적용을 하지만,
CRA 를 통해 만든 리액트 프로젝트에서는 package.json 에서 "proxy" 값을 설정하여 쉽게 적용 할 수 있다.

package.json의 맨 아래에 다음과 같이 "proxy" 값을 설정하자.

//package.json
  (...),
  "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:4000"
}

그 다음에는, api/posts.js 파일을 열어서 http://localhost:4000/posts 대신에 /posts URL 로 요청을 하도록 하면 된다.
이렇게 요청하는 주소의 도메인이 생략된 경우엔 현재 페이지의 도메인(지금의 경우 http://localhost:3000)을 가르키게 된다.

webpack으로 설정하는 경우
.
서버 응답 헤더를 추가할 필요없이 웹팩 개발 서버에서 api 서버로 프록싱할 수 있다.
웹팩 개발 서버는 proxy 속성으로 이를 지원한다.

// webpack.config.js
module.exports = {
  devServer: {
    proxy: {
      "/api": "http://localhost:8081", // 프록시
    },
  },
}

개발서버에 들어온 모든 http 요청중 /api로 시작되는것은 http://localhost:8081로 요청하는 설정이다. api 호출코드를 다시 복구한 뒤,

// src/model.js
const model = {
  async get() {
    // const { data } = await axios.get('http://localhost:8081/api/keywords');

    const { data } = await axios.get("/api/keywords")
    return data
  },
}

확인해보면 정상 동작하는 것을 확인할 수 있다.


참고링크