๐Ÿš€ ํด๋ผ์ด์–ธํŠธ ์ธก vs ์„œ๋ฒ„ ์ธก CORS: ์‹ค์ œ ์ฐจ์ด์  ์ดํ•ดํ•˜๊ธฐ

๋ฐœํ–‰: (2025๋…„ 12์›” 5์ผ ์˜ค์ „ 05:49 GMT+9)
6 min read
์›๋ฌธ: Dev.to

Source: Dev.to

๐Ÿš€ ํด๋ผ์ด์–ธํŠธ ์ธก vs ์„œ๋ฒ„ ์ธก CORS: ์‹ค์ œ ์ฐจ์ด์  ์ดํ•ดํ•˜๊ธฐ ํ‘œ์ง€ ์ด๋ฏธ์ง€

๋ชจ๋‹ˆํ„ฐ ์•ž์—์„œ ์ˆ˜์ˆ˜๊ป˜๋ผ ๊ฐ™์€ CORS ์˜ค๋ฅ˜ ๋•Œ๋ฌธ์— ์†Œ๋ฆฌ๋ฅผ ์งˆ๋Ÿฌ ๋ณธ ์ ์ด ์žˆ๋‹ค๋ฉดโ€ฆ
์ถ•ํ•˜ํ•ฉ๋‹ˆ๋‹ค โ€” ์ด์ œ ๊ณต์‹์ ์ธ ์›น ๊ฐœ๋ฐœ์ž์ž…๋‹ˆ๋‹ค. ๐ŸŽ‰

CORS๋Š” ๋งˆ์น˜ ํด๋Ÿฝ ์•ž์— ์„œ ์žˆ๋Š” ์—„๊ฒฉํ•œ ๊ฒฝ๋น„์›๊ณผ ๊ฐ™์•„์„œ, ๋‹น์‹ ์ด ๋ชฉ๋ก์— ์žˆ๋‹ค๊ณ  ๋งน์„ธํ•ด๋„ ๋“ค์–ด๊ฐ€์ง€ ๋ชปํ•˜๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.

CORS๊ฐ€ ์‹ค์ œ๋กœ ๋ญ”๊ฐ€์š”?

CORS๋Š” Crossโ€‘Origin Resource Sharing์˜ ์•ฝ์ž์ž…๋‹ˆ๋‹ค โ€” ๋ฉ‹์ ธ ๋ณด์ด์ง€๋งŒ ์‹ค์ œ ์˜๋ฏธ๋Š”:

โ€œ๋ธŒ๋ผ์šฐ์ €์•ผ, ์ด ์›น์‚ฌ์ดํŠธ๊ฐ€ ์ € ๋‹ค๋ฅธ ์›น์‚ฌ์ดํŠธ์™€ ๋Œ€ํ™”ํ•ด๋„ ๋ ๊นŒ? ์•„๋‹ˆ๋ฉด ๋‚ฏ์„  ์‚ฌ๋žŒ ์œ„ํ—˜ ์ƒํ™ฉ์ธ๊ฐ€?โ€

๋ธŒ๋ผ์šฐ์ €๋Š” ๋งค์šฐ ํŽธ์ง‘์ฆ์ ์ž…๋‹ˆ๋‹ค.
๋„๋ฉ”์ธ A๊ฐ€ ๋„๋ฉ”์ธ B๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ๋ธŒ๋ผ์šฐ์ €๋Š” ์ด๋ ‡๊ฒŒ ๋งํ•ฉ๋‹ˆ๋‹ค:

โ€œ์ž ๊น. ๋ˆ„๊ฐ€ ๋ณด๋ƒˆ์–ด? ์—ฌ๊ถŒ, ์•„๋‹ค๋ฅด ์นด๋“œ, PAN ์นด๋“œ, ๊ทธ๋ฆฌ๊ณ  2ร—2 ์‚ฌ์ง„ ๋‘ ์žฅ ๋ณด์—ฌ์ค˜.โ€

ํด๋ผ์ด์–ธํŠธโ€‘์ธก vs ์„œ๋ฒ„โ€‘์ธก CORS: ๋ฐ˜์ „

์‚ฌ๋žŒ๋“ค์€ *โ€œํด๋ผ์ด์–ธํŠธโ€‘์ธก CORSโ€*์™€ *โ€œ์„œ๋ฒ„โ€‘์ธก CORSโ€*๋ฅผ ์–˜๊ธฐํ•˜์ง€๋งŒ, ์ง„์‹ค์€:

CORS๋ฅผ ๊ฒฐ์ •ํ•˜๋Š” ๊ฒƒ์€ ์˜ค์ง ์„œ๋ฒ„๋ฟ์ž…๋‹ˆ๋‹ค. ํด๋ผ์ด์–ธํŠธ๋Š” ํ—ˆ๊ฐ€๋ฅผ ์š”์ฒญํ•˜๋Š” ํ˜ผ๋ž€์Šค๋Ÿฌ์šด ์ฒญ์†Œ๋…„์ผ ๋ฟ.

์–‘์ชฝ ๋ชจ๋‘ ์—ญํ• ์„ ํ•˜๋‹ˆ, ์ด์ œ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

ํด๋ผ์ด์–ธํŠธโ€‘์ธก CORS (์ผ๋ช…: ์ œ์–ด์˜ ์ฐฉ๊ฐ)

๊ฐœ๋ฐœ์ž๋“ค์€ ์ข…์ข… ์ด๋ ‡๊ฒŒ ์”๋‹ˆ๋‹ค:

fetch("/api", { mode: "cors" })

๊ทธ๋ฆฌ๊ณ  ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์ด๋ ‡๊ฒŒ ๋งํ•ด ์ฃผ๊ธธ ๊ธฐ๋Œ€ํ•ฉ๋‹ˆ๋‹ค:

โ€œ๋„ค, ์•Œ๊ฒ ์Šต๋‹ˆ๋‹ค! CORS๊ฐ€ ํ™œ์„ฑํ™”๋˜์—ˆ์Šต๋‹ˆ๋‹ค! ๋‹น์‹ ์€ ์ฒœ์žฌ๊ตฐ์š”!โ€

ํ•˜์ง€๋งŒ ์‹ค์ œ๋กœ ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ๊ทœ์น™์„ ์ง‘ํ–‰ํ•ฉ๋‹ˆ๋‹ค:

  • mode: "cors" โ†’ โ€œ์ œ๋ฐœ ๋“ค์–ด๊ฐ€๊ฒŒ ํ•ด ์ฃผ์„ธ์š”!โ€
  • mode: "no-cors" โ†’ โ€œ์•Œ๊ฒ ์–ด์š”, ๋– ๋‚ ๊ฒŒ์š”. ์–ด์ฐจํ”ผ ์‘๋‹ต์„ ๋ณด๊ณ  ์‹ถ์ง€ ์•Š์•˜๊ฑฐ๋“ ์š”.โ€
  • credentials: "include" โ†’ โ€œ์ฟ ํ‚ค ์—ฌ๊ธฐ ์žˆ์–ด์š”, ํŒ๋‹จ์€ ํ•˜์ง€ ๋ง์•„ ์ฃผ์„ธ์š”.โ€

โš ๏ธ ํด๋ผ์ด์–ธํŠธ๋Š” CORS๋ฅผ ํ™œ์„ฑํ™”ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์š”์ฒญ๋งŒ ํ•  ์ˆ˜ ์žˆ์„ ๋ฟ์ด๋ฉฐ, ํ‚ค๋Š” ์—ฌ์ „ํžˆ ์„œ๋ฒ„์— ์žˆ์Šต๋‹ˆ๋‹ค.

์„œ๋ฒ„โ€‘์ธก CORS (์ง„์งœ ๋ณด์Šค)

์—ฌ๊ธฐ๊ฐ€ ์‹ค์ œ ๋งˆ๋ฒ•์ด ์ผ์–ด๋‚˜๋Š” ๊ณณ์ž…๋‹ˆ๋‹ค. ์„œ๋ฒ„๊ฐ€ ๋‹น์‹ ์˜ ์˜ค๋ฆฌ์ง„์„ ์Šน์ธํ•˜์ง€ ์•Š์œผ๋ฉด ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์š”์ฒญ์„ ์ฐจ๋‹จํ•ฉ๋‹ˆ๋‹ค.

์ผ๋ฐ˜์ ์ธ ์‘๋‹ต ํ—ค๋”:

Access-Control-Allow-Origin: https://myapp.com
Access-Control-Allow-Methods: GET, POST, DELETE
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Allow-Credentials: true

์˜ฌ๋ฐ”๋ฅธ ํ—ค๋”๋ฅผ ๋ฐ›์€ ๋’ค์—์•ผ ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์š”์ฒญ์„ ํ—ˆ์šฉํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ์‹œ (Express.js)

const cors = require('cors');

app.use(cors({
  origin: "https://myapp.com",
  credentials: true
}));

์˜ˆ์‹œ (Next.js API ๋ผ์šฐํŠธ)

export default function handler(req, res) {
  res.setHeader("Access-Control-Allow-Origin", "https://myapp.com");
  res.setHeader("Access-Control-Allow-Credentials", "true");
  // ...์š”์ฒญ ์ฒ˜๋ฆฌ
}

ํ—ค๋” ํ•˜๋‚˜๋ผ๋„ ๋นผ๋จน์œผ๋ฉด CORS ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

Simple vs Preflight ์š”์ฒญ (์ผ๋ช…: ๋ธŒ๋ผ์šฐ์ € ๋“œ๋ผ๋งˆ)

Simple ์š”์ฒญ

์ด๊ฒƒ๋“ค์€ โ€œํŽธ์•ˆํ•จโ€์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ํ—ˆ์šฉํ•˜๋Š” ๊ฒฝ์šฐ:

  • GET ๋˜๋Š” POST์™€ ๋‹จ์ˆœ ํ—ค๋”(Accept, Content-Type์ด text/plain, multipart/form-data, application/x-www-form-urlencoded ์ค‘ ํ•˜๋‚˜์ธ ๊ฒฝ์šฐ)

Preflight ์š”์ฒญ

๋‹ค์Œ ์ƒํ™ฉ์—์„œ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค:

  • PUT, PATCH, DELETE ๊ฐ™์€ ๋ฉ”์„œ๋“œ ์‚ฌ์šฉ
  • ์ปค์Šคํ…€ ํ—ค๋”
  • JSON ๋ฐ”๋””(Content-Type: application/json)

๋ธŒ๋ผ์šฐ์ €๋Š” ๋จผ์ € OPTIONS ์š”์ฒญ์„ ๋ณด๋‚ด ์„œ๋ฒ„์—๊ฒŒ ํ—ˆ๊ฐ€๋ฅผ ๋ฌป์Šต๋‹ˆ๋‹ค. ์„œ๋ฒ„๊ฐ€ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์‘๋‹ตํ•˜์ง€ ์•Š์œผ๋ฉด ์‹ค์ œ ์š”์ฒญ์ด ์ฐจ๋‹จ๋ฉ๋‹ˆ๋‹ค.

๋„ˆ๋ฌด ๋นจ๋ฆฌ ์Šคํฌ๋กคํ•œ ์ฒœ์žฌ๋“ค์„ ์œ„ํ•œ ์š”์•ฝ ํ‘œ

ํ•ญ๋ชฉํด๋ผ์ด์–ธํŠธ ์ธก์„œ๋ฒ„ ์ธก
๋ˆ„๊ฐ€ ์ œ์–ดํ•˜๋‚˜์š”?์›ƒ์Œ. ๋‹น์‹ ์ด ์•„๋‹™๋‹ˆ๋‹ค.์ง„์งœ ๋ณด์Šค.
์š”์ฒญ์„ ํ—ˆ์šฉํ•  ์ˆ˜ ์žˆ๋‚˜์š”?โŒ ์•ˆ ๋ฉ๋‹ˆ๋‹คโœ… ๋ฌผ๋ก  ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค
Preflight๋ฅผ ํŠธ๋ฆฌ๊ฑฐํ•  ์ˆ˜ ์žˆ๋‚˜์š”?โœ… ์˜ˆโš ๏ธ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์‘๋‹ตํ•ด์•ผ ํ•จ
์ง„์งœ CORS์ธ๊ฐ€์š”?โŒ ์•„๋‹ˆ์š”โœ… ๋„ค, 100โ€ฏ% ์ •ํ†ต

๋งˆ๋ฌด๋ฆฌ ์ƒ๊ฐ

CORS ์˜ค๋ฅ˜๋Š” ๋งˆ์น˜ ์šฐ์ฃผ๊ฐ€ ๊ฐœ์ธ์—๊ฒŒ ๊ณต๊ฒฉ์„ ๊ฐ€ํ•˜๋Š” ๋“ฏํ•œ ๋А๋‚Œ์„ ์ค„ ์ˆ˜ ์žˆ์ง€๋งŒ, ๊ทœ์น™์€ ๊ฐ„๋‹จํ•ฉ๋‹ˆ๋‹ค:

  1. ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์š”์ฒญ์„ ๋ณด๋ƒ…๋‹ˆ๋‹ค.
  2. ์„œ๋ฒ„๊ฐ€ ์ ์ ˆํ•œ ํ—ค๋”๋ฅผ ๋ณด๋‚ด ํ—ˆ์šฉ ์—ฌ๋ถ€๋ฅผ ๊ฒฐ์ •ํ•ฉ๋‹ˆ๋‹ค.
  3. ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ๊ทธ ๊ฒฐ์ •์„ ๊ฐ•์ œํ•ฉ๋‹ˆ๋‹ค.

๊ฐ ํŒŒํŠธ๊ฐ€ ์ œ ์—ญํ• ์„ ํ•˜๋ฉด CORS๋Š” ๊ณ ํ†ต์ด ์—†์Šต๋‹ˆ๋‹ค. ๋ญ”๊ฐ€ ์ž˜๋ชป๋˜๋ฉดโ€ฆ ๋‹ค์Œ ๋ช‡ ์‹œ๊ฐ„ ๋™์•ˆ ๋””๋ฒ„๊น…์„ ์ฆ๊ธฐ์„ธ์š”. ๐Ÿ˜…

Back to Blog

๊ด€๋ จ ๊ธ€

๋” ๋ณด๊ธฐ ยป

JavaScript๋กœ ์ด๋ฉ”์ผ ๋ณด๋‚ด๋Š” ๋ฐฉ๋ฒ•: SendLayer API ์™„์ „ ๊ฐ€์ด๋“œ

JavaScript๋กœ ์ด๋ฉ”์ผ ๋ณด๋‚ด๋Š” ๋ฐฉ๋ฒ• ์•ž์„œ ์–ธ๊ธ‰ํ–ˆ๋“ฏ์ด, JavaScript๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํด๋ผ์ด์–ธํŠธ ์ธก๊ณผ ๋ฐฑ์—”๋“œ ์„œ๋ฒ„ ๋ชจ๋‘์—์„œ ์ด๋ฉ”์ผ์„ ๋ณด๋‚ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ €๋Š” ์–‘์ชฝ์„ ๋‹ค๋ฃฐ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์Šค์บ๋„ˆ ์ง€์›์ด ํฌํ•จ๋œ ๋ฌด๋ฃŒ ์›น ๊ธฐ๋ฐ˜ ๋ฌธ์„œ ๋ณ€ํ™˜๊ธฐ ๊ตฌ์ถ•

์˜ค๋Š˜๋‚  ๋””์ง€ํ„ธ ์„ธ๊ณ„์—์„œ๋Š” ๋‹ค์–‘ํ•œ ์ถœ์ฒ˜์˜ ๋ฌธ์„œ๋ฅผ ๋ณ€ํ™˜ํ•˜๊ณ , ๋ณ‘ํ•ฉํ•˜๋ฉฐ, ํŽธ์ง‘ํ•ด์•ผ ํ•  ํ•„์š”๊ฐ€ ์ž์ฃผ ์žˆ์Šต๋‹ˆ๋‹ค. PDF, Word ๋ฌธ์„œ, ์ด๋ฏธ์ง€ ๋“ฑ์„ ๋‹ค๋ฃฐ ๋•Œ...

SaaS IA ๋‰ด์Šค

SaaS IA ๋‰ด์Šค์šฉ ์ปค๋ฒ„ ์ด๋ฏธ์ง€ https://media2.dev.to/dynamic/image/width=1000,height=420,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazon...