node.js express corsnode express corsnode.js cors 설정node.js cors errorbackend

Node.js, Express.js 에서 CORS 이해와 설정 방법

KUKJIN LEE
KUKJIN LEE
2024년 2월 19일
549

CORS(Cross-Origin Resource Sharing)는 웹 페이지가 다른 도메인의 리소스를 요청하는 것을 가능하게 하는 웹 보안 표준입니다.

웹 브라우저는 기본적으로 보안 상 Same-Origin Policy를 따르기 때문에, 현재 웹 페이지와 다른 출처에서 오는 리소스에 대한 요청은 제한됩니다.

이 때문에, 웹 페이지가 다른 도메인의 API를 요청하려면 CORS 설정이 필요하게 됩니다.

Node.js에서의 CORS 설정

Node.js에서 CORS 설정을 위해 'cors' 라이브러리를 사용할 수 있습니다. 먼저, 이 라이브러리를 설치해야 합니다.

npm install cors

가장 기본적인 CORS 설정

모든 도메인에서 들어오는 요청을 허용하도록 설정합니다.

하지만 모든 도메인에서 들어오는 요청을 허용하게 될 경우, 문제가 발생할 수 있기 때문에 세부 설정을 진행해야합니다.

문제란, 다른 도메인에서 리소스를 요청하는 경우를 얘기합니다.

const express = require('express');
const cors = require('cors');
const app = express();

app.use(cors());

CORS 초급 설정

보다 세부적인 설정을 하려면, 'cors' 함수에 옵션 객체를 전달할 수 있습니다.

'origin' 속성에 허용하고 싶은 도메인을 지정할 수 있습니다. 또한, 'credentials' 속성을 'true'로 설정하면, 이 도메인에서의 요청이 쿠키와 같은 자격 증명을 포함하도록 허용합니다.

이렇게 설정하면, 브라우저가 서버에 요청을 보낼 때 'Access-Control-Allow-Origin'과 'Access-Control-Allow-Credentials' 헤더가 추가되어, CORS 정책을 준수하게 됩니다.

이상으로 Node.js에서 CORS를 설정하는 방법에 대해 알아봤습니다. 이 기능을 활용하면, 안전하게 다른 도메인의 리소스를 요청하고 사용할 수 있습니다.

app.use(
  cors({
    origin: 'http://localhost:3300',
    credentials: true,
  }),
);

CORS 세부 설정

  1. origin: 클라이언트 사이트의 URL을 지정합니다. 이 경우, http://localhost:3300에서 오는 요청만 허용됩니다.
  2. methods: 허용할 HTTP 메서드를 지정합니다. 이 경우, GET과 POST 메서드를 사용하는 요청만 허용됩니다.
  3. allowedHeaders: 서버가 수락할 수 있는 요청 헤더를 지정합니다. 이 경우, 요청 헤더에 Content-Type과 Authorization이 포함되어야 합니다. 
  4. credentials: 응답 헤더에 Access-Control-Allow-Credentials를 추가합니다. 이 경우, 요청이 쿠키 및 인증 정보를 포함할 수 있습니다.
  5. maxAge: 사전 전달 요청의 결과를 캐시할 시간을 초 단위로 지정합니다. 이 경우, 사전 전달 요청의 결과는 600초 동안 캐시됩니다. 
const express = require('express');
const cors = require('cors');
const app = express();

app.use(
  cors({
    origin: 'http://localhost:3300',
    methods: ['GET', 'POST'],
    allowedHeaders: ['Content-Type', 'Authorization'],
    credentials: true,
    maxAge: 600,
  }),
);

allowedHeaders 예시

try문 내부에 headers 설정을 확인할 수 있습니다.

async function sendData() {
  try {
    const response = await fetch('http://localhost:3300/sample', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        Authorization: 'token sample',
      },
      body: JSON.stringify({
        title: 'title',
        description: 'description',
      }),
    })

    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`)
    }

    const data = await response.json()
    console.log(data)
  } catch (error) {
    console.error('Error:', error)
  }
}

sendData()

credentials 예시

credentials: 'include' 설정하면 클라이언트는 쿠키를 요청에 포함시킬 수 있습니다.

반대로 'omit'으로 설정하면, 클라이언트는 쿠키를 요청에 포함시키지 않습니다.

서버에서 credentials: true를 설정했다고 반드시 자격 증명을 포함해야 하는 건 아닙니다. 반대로 credentials가 false경우에는 자격 증명을 포함 할 수 없습니다.

fetch('http://localhost:3300/sample', {
  method: 'GET',
  credentials: 'include',
})

fetch('http://localhost:3300/sample', {
  method: 'GET',
  credentials: 'omit',
})

maxAge

maxAge를 사용하면 동일한 요청에 대해 서버에게 불필요한 요청을 막는 시간값입니다.

즉 Preflight 요청은 실제 요청을 보내기 전에 보내지는 요청으로, 서버가 해당 요청을 처리할 수 있는지 확인하고 HTTP OPTIONS 메서드를 사용합니다.

maxAge는 캐시 시간을 뜻하고 위 예시에서 600을 입력했으니까, 10분 동안 요청에 대한 결과를 가지고 있으니, 다시 요청할거면 10분동안 요청을 보낼 수 없게 막아버립니다.

이렇게하면 동일한 요청에 대해 서버에게 불필요한 preflight 요청을 줄일 수 있습니다.

하지만 maxAge를 사용하더라도 클라이언트는 캐시를 무시하고 preflight 요청을 계속 다시 보낼 수 있습니다.

관련 글

[SQL 입문] 필요한 데이터만 콕 집어 가져올 수 있는 WHERE 절

사용자는 테이블에 있는 모든 데이터를 다 보고 싶어 하지는 않습니다. 오히려 특정 항목에 대한 데이터만 가져오고 싶을 때가 훨씬 많습니다. 예를 들어, 어떤 사용자의 이메일이나 ID는 알고 있는데, 그 사람이 언제 우리 앱에 가입했는지 확인하고 싶다고 가정해 봅시다...

2026년 1월 27일10

SQL에서 SELECT란 무엇인가?

데이터베이스를 거대한 서류 보관함이라고 생각하면 됩니다. 보관함 안에는 수많은 데이터가 차곡차곡 쌓입니다. SELECT는 이 보관함에서 "내가 원하는 정보를 찾아줘!"라고 요청하는 명령어입니다. 이 과정을 전문 용어로 '쿼리(Query)'라고 부릅니다. &nbs...

2026년 1월 26일10

[SQL 기초] "언제 하나씩 다 넣어?" 데이터 한 번에 넣기

개발을 하다 보면 데이터베이스(DB)에 샘플 데이터를 대량으로 넣어야 할 때가 있습니다. 메뉴 100개를 추가해야 하는데 INSERT 문을 100번 쓰고 있다면? 너무 비효율적이죠! 오늘은 SQL에서 여러 데이터를 한 번에 넣는 '다중 삽입(Multiple Inse...

2026년 1월 21일13

SQL 데이터 삽입하기

데이터가 없는 데이터베이스는 연료 없는 로켓과 같습니다. 이제 'Missions' 테이블에 새로운 행(row)을 추가하는 방법을 알아보겠습니다. "삽입(Inserting)"은 '데이터 추가'를 의미합니다. 기존 Missions 테이블 ...

2026년 1월 20일12