No 'Access-Control-Allow-Origin' header is present on the requested resource

문제 상황

Issue Tracker React 프로젝트에서 axios를 사용하여 백엔드 서버에 POST 요청시 아래와 같은 에러가 발생했다.

Access to XMLHttpRequest at 'http://.../api/labels' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.

  • 에러는 production이 아닌 development 모드에서 발생함
  • CRA를 사용하지 않고 webpack-dev-server를 사용하여 프로젝트 환경을 커스텀한 상태
  • webpack-dev-server 설정은 다음과 같다.

webpack.dev.js

const merge = require("webpack-merge");
const common = require("./webpack.common.js");

module.exports = merge(common, {
  mode: "development",
  devtool: "inline-source-map",
  devServer: {
    historyApiFallback: true,
    inline: true,
    port: 3000,
    hot: true,
    publicPath: "/",
    open: true,
  },
});

Chrome DevTools Network 탭에서 확인해보니 OPTIONS, POST 총 2번의 요청을 보냈고,

img1

각각의 Header를 살펴보니 다음과 같았다.

OPTIONS 요청 img3

POST 요청 img2


원인 파악

문제는 외부에 있는 백엔드 서버에 POST 요청을 보내기 위해 preflight 요청을 먼저 보내서 POST 요청 권한 유무를 확인했는데, 이때 권한이 없다는 응답(403)을 받아서 POST 요청을 보내지 못했기 때문이었다.


해결 방안 탐색

CORS 관련 webpack의 ‘proxy’ 설정에 대해 알게되었다.

proxy 설정은 외부 도메인에 대한 요청과 응답을 webpack 또는 webpack-dev-server가 처리할 수 있게 해주는 옵션이다. 쉽게 얘기하면 외부 도메인으로 보내는 요청을 가로채서 외부 백엔드 서버로 전달하고, 다시 백엔드 서버로부터 온 응답을 가로채서 브라우저쪽으로 반환해주는 것이다.

요청과 응답을 가로채서 필요에 따라 ‘적절한 처리’를 해줄 수 있기 때문에 백엔드의 코드를 수정하지 않고도 CORS 이슈를 해결하는 방법이 될 수 있다.

CRA를 사용하는 경우 package.json에 proxy 설정을 추가해주면 되고, dev-server를 사용하는 경우 webpack config 파일에서 devServer 설정값으로 proxy를 추가해주면 된다.

관련 자료들

CRA

webpack-dev-server


해결

이번 CORS 이슈는 백엔드에서 Spring에 다음과 같은 설정을 추가한뒤 해결됐다.

WebConfig.java

(...)

@Override
  public void addCorsMappings(CorsRegistry registry) {
    registry.addMapping("/**")
        .allowedMethods("GET", "POST", "PUT", "PATCH", "DELETE")
        .allowedOrigins("http://localhost:3000");
  }

배운 점 / 느낀 점

  • 외부 도메인에 GET, POST, PUT 등의 요청을 보낼 때 OPTIONS라는 메서드로 preflight 요청을 먼저 보내서 해당 도메인으로 GET, POST, PUT 등의 요청을 보낼 수 있는지를 먼저 확인한다는걸 배웠다.
  • webpack / webpack-dev-server의 proxy라는 설정과 관련 자료들을 찾아보면서 http, 네트워크 공부의 필요성을 절감했고 추가로 공부해볼 내용들을 정리할 수 있었다.

    • Request/Response header 프로퍼티가 각각 어떤 의미를 가지고 어떤 기능을 하는지
    • CORS와 관련된 header 프로퍼티는 무엇이며 어떻게 설정해주어야 하는지 (프론트 webpack 설정이나 백엔드에서)

@Reese
Sin Prosa Sin Pausa