Front End/Web

Proxy

๐ŸŒ

CORS ์ •์ฑ…์˜ ํ•„์š”์„ฑ

CORS (๊ต์ฐจ ์ถœ์ฒ˜ ๋ฆฌ์†Œ์Šค ๊ณต์œ , Cross-Origin Resource Sharing) CORS๋Š” ์ถ”๊ฐ€ย HTTP ํ—ค๋”๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ, ํ•œย ์ถœ์ฒ˜์—์„œ ์‹คํ–‰ ์ค‘์ธ ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ๋‹ค๋ฅธ ์ถœ์ฒ˜์˜ ์„ ํƒํ•œ ์ž์›์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋Š” ๊ถŒํ•œ์„ ๋ถ€์—ฌํ•˜๋„๋ก ๋ธŒ๋ผ์šฐ์ €์— ์•Œ๋ ค์ฃผ๋Š” ์ฒด์ œ์ด๋‹ค.

์‹ค์ œ ์„œ๋น„์Šค๊ฐ€ ๋˜๋Š” ์ƒ์šฉ ์•ฑ์„ ์šด์˜ํ•œ๋‹ค๋ฉด, ํด๋ผ์ด์–ธํŠธ ๋’ค์— ์žˆ๋Š” ์„œ๋ฒ„์™€ ์—ฐ๊ฒฐ๋œ DB์—๋Š” ๋ผ์ด๋ธŒ ๋ฐ์ดํ„ฐ๊ฐ€ ์Œ“์ธ๋‹ค. ์ด๋Ÿฐ ๋ผ์ด๋ธŒ ๋ฐ์ดํ„ฐ๋Š” ๋ฏผ๊ฐ์„ฑ์ด ๋†’์€ ๋ฐ์ดํ„ฐ๋“ค ์œ„์ฃผ๋กœ ์ด๋ฃจ์–ด์ ธ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์„œ๋ฒ„์—์„œ ๋ชจ๋“  ์ถœ์ฒ˜์˜ ์ ‘๊ทผ์„ ํ—ˆ์šฉํ•œ๋‹ค๋ฉด ๋ณด์•ˆ์„ฑ์ด ๋‚ฎ์•„์ง€๊ณ  ํ•ดํ‚น์˜ ์œ„ํ—˜์— ๊ทธ๋Œ€๋กœ ๋…ธ์ถœ๋œ๋‹ค.

์ด๋ฅผ ์œ„ํ•ด์„œ๋Š” ํŠน์ • ๋„๋ฉ”์ธ๋งŒ ํ—ˆ์šฉํ•˜๋„๋ก ๊ฐ ๊ฐœ๋ฐœ์ž ๊ฐ„ ํ˜‘์˜๊ฐ€ ํ•„์š”ํ•˜๋‹ค. ํด๋ผ์ด์–ธํŠธ(ํ”„๋ก ํŠธ) ๊ฐœ๋ฐœ์ž๋Š” ๊ฐœ๋ฐœ ์„œ๋ฒ„ ๋„๋ฉ”์ธ์„ ํ—ˆ์šฉํ•ด๋‹ฌ๋ผ ์š”์ฒญํ•˜๊ณ , ์„œ๋ฒ„(๋ฐฑ์—”๋“œ) ๊ฐœ๋ฐœ์ž๋Š” ํ•ด๋‹น ๋„๋ฉ”์ธ๋งŒ ์ ‘๊ทผ์ด ๊ฐ€๋Šฅํ•˜๋„๋ก CORS ํ—ค๋” ์„ค์ •์„ ํ•˜๋ฉด ๋œ๋‹ค.

Proxy

ํ”„๋ก์‹œ ์„œ๋ฒ„๋Š” ํด๋ผ์ด์–ธํŠธ์™€ ์„œ๋ฒ„ ์‚ฌ์ด์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌํ•ด์ฃผ๋Š” ์—ญํ• ์„ ํ•˜๋Š” ์ผ์ข…์˜ ์ค‘๊ณ„ ์„œ๋ฒ„์ด๋‹ค. ํ•ด๋‹น ๊ตญ๊ฐ€ IP๋ฅผ ์šฐํšŒํ•˜๊ฑฐ๋‚˜ ์„œ๋ฒ„์ธก์—์„œ ์ฐจ๋‹จํ•œ IP๋ฅผ ์šฐํšŒํ•˜๋Š” ๋“ฑ ๋งŽ์€ ๊ณณ์—์„œ ์‚ฌ์šฉ์ด ๊ฐ€๋Šฅํ•˜์ง€๋งŒ(์•ˆ์ข‹์€ ์ชฝ์œผ๋กœ๋„), ์›น ๊ฐœ๋ฐœ ์‹œ์—๋Š” CORS ์ •์ฑ…์„ ์šฐํšŒํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•˜๊ธฐ๋„ ํ•œ๋‹ค. React ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ, ํ˜น์€ Webpack Dev Server์—์„œ Proxy ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜๊ณ  ์žˆ๋‹ค.

proxy ์ ์šฉ ์ „์˜ ํ๋ฆ„
proxy ์ ์šฉ ํ›„์˜ ํ๋ฆ„

proxy๋ฅผ ์ ์šฉํ•˜๊ธฐ ์ „์—๋Š” React ์•ฑ์—์„œ ๋ธŒ๋ผ์šฐ์ €์ชฝ์œผ๋กœ ์š”์ฒญ์„ ๋ณด๋‚ด๊ฒŒ ๋œ๋‹ค. ๋ธŒ๋ผ์šฐ์ €๋Š” ์„œ๋ฒ„์— ์š”์ฒญ์„ ๋ณด๋‚ผ ๋•Œ ์ ‘๊ทผ ๊ถŒํ•œ์ด ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๋Š”๋ฐ, ์„œ๋ฒ„๊ฐ€ ์ •์ƒ์ ์œผ๋กœ 200 OK ์‘๋‹ต์„ ๋ณด๋‚ด๋”๋ผ๋„ ๋ธŒ๋ผ์šฐ์ €๋Š” ์ถœ์ฒ˜๊ฐ€ ๊ฐ™์€์ง€ ํ™•์ธํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ถœ์ฒ˜๊ฐ€ ๋‹ค๋ฅด๋ฉด ์‘๋‹ต์„ ํŒŒ๊ธฐ(CORS Error) ํ•˜๊ฒŒ ๋œ๋‹ค.

proxy๋ฅผ ์ ์šฉํ•˜๊ฒŒ ๋˜๋ฉด React ์•ฑ์—์„œ proxy๋ฅผ ํ†ตํ•ด ์„œ๋ฒ„๋กœ ์š”์ฒญ์„ ์šฐํšŒํ•˜์—ฌ ๋ณด๋‚ด๊ฒŒ ๋œ๋‹ค. ์„œ๋ฒ„๋Š” ์‘๋‹ต์„ React ์•ฑ์œผ๋กœ ๋ณด๋‚ด๊ณ , React ์•ฑ์€ ๋ฐฑ์—”๋“œ ์„œ๋ฒ„ ๋Œ€์‹  ๋ธŒ๋ผ์šฐ์ €์—๊ฒŒ ์ „๋‹ฌํ•œ๋‹ค. React ์•ฑ์€ ๊ฒฐ๊ตญ ํด๋ผ์ด์–ธํŠธ์™€ ๋™์ผ ์ถœ์ฒ˜์ด๊ธฐ ๋•Œ๋ฌธ์— ๋ธŒ๋ผ์šฐ์ €๋Š” ์ด ์‚ฌ์‹ค์„ ๋ˆˆ์น˜ ์ฑ„์ง€ ๋ชปํ•˜๊ณ  ํ—ˆ์šฉํ•˜๊ฒŒ ๋œ๋‹ค.

webpack dev server proxy ์‚ฌ์šฉ๋ฒ•

webpack dev server์—์„œ ์ œ๊ณตํ•˜๋Š” proxy ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜๊ฒŒ ๋˜๋ฉด, ๋ธŒ๋ผ์šฐ์ € API๋ฅผ ์š”์ฒญํ•  ๋•Œ ๋ฐฑ์—”๋“œ ์„œ๋ฒ„์— ์ง์ ‘ ์š”์ฒญ์„ ๋ณด๋‚ด์ง€ ์•Š๊ณ  ํ˜„์žฌ ๊ฐœ๋ฐœ์„œ๋ฒ„์˜ ์ฃผ์†Œ๋กœ ์šฐํšŒ ์š”์ฒญ์„ ๋ณด๋‚ธ๋‹ค. ์›นํŒฉ ๊ฐœ๋ฐœ ์„œ๋ฒ„์—์„œ๋Š” ํ•ด๋‹น ์š”์ฒญ์„ ๋ฐ›์•„ ๊ทธ๋Œ€๋กœ ๋ฐฑ์—”๋“œ ์„œ๋ฒ„๋กœ ์ „๋‹ฌํ•˜๊ณ , ๋ฐฑ์—”๋“œ ์„œ๋ฒ„์—์„œ ์‘๋‹ตํ•œ ๋‚ด์šฉ์„ ๋‹ค์‹œ ๋ธŒ๋ผ์šฐ์ €๋กœ ๋ฐ˜ํ™˜ํ•˜๊ฒŒ ๋œ๋‹ค.

...
"browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  },
	"proxy" : "์šฐํšŒํ•  API ์ฃผ์†Œ"
}

์›นํŒฉ ๊ฐœ๋ฐœ์„œ๋ฒ„์˜ proxy ์„ค์ •์€ ์›๋ž˜ ์›นํŒฉ ์„ค์ •์„ ํ†ตํ•ด์„œ ์ ์šฉ์„ ํ•˜์ง€๋งŒ, CRA๋ฅผ ํ†ตํ•ด ๋งŒ๋“  ๋ฆฌ์•กํŠธ ํ”„๋กœ์ ํŠธ์—์„œ๋Š” ์œ„์˜ ์ฝ”๋“œ์ฒ˜๋Ÿผ package.json์—์„œ โ€œproxyโ€ ๊ฐ’์„ ์„ค์ •ํ•˜๋ฉด ํ”„๋ก์‹œ ์„ค์ •์ด ๊ฐ€๋Šฅํ•˜๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๊ธฐ์กด์˜ fetch๋‚˜ axios๋ฅผ ํ†ตํ•ด ์š”์ฒญ์„ ๋ณด๋‚ด๋˜ ๋ถ€๋ถ„์—์„œ ๋„๋ฉ”์ธ ๋ถ€๋ถ„์„ ์ œ๊ฑฐํ•˜๋ฉด ๋œ๋‹ค.

export async function getAllfetch() {
    const response = await fetch('์šฐํšŒํ•  api์ฃผ์†Œ/params');
    .then(() => {
			...
		})
}

// proxy ์„ค์ • ํ›„
export async function getAllfetch() {
    const response = await fetch('/params');
    .then(() => {
			...
		})
}

React Proxy ์‚ฌ์šฉ๋ฒ•

webpack dev server์—์„œ ์ œ๊ณตํ•˜๋Š” proxy๋Š” ์ „์—ญ์ ์ธ ์„ค์ •์ด๊ธฐ ๋•Œ๋ฌธ์— ์ข…์ข… ํ•ด๋‹น ๋ฐฉ๋ฒ•์ด ์ถฉ๋ถ„ํžˆ ์ ์šฉ๋˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ๊ฐ€ ์ƒ๊ธฐ๊ธฐ๋„ ํ•œ๋‹ค. ๊ทธ๋ž˜์„œ ์ˆ˜๋™์œผ๋กœ proxy๋ฅผ ์ ์šฉํ•ด์ค˜์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ๋Š”๋ฐ, ์ด ๋•Œ๋Š” http-proxy-middleware ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.

  • http-proxy-middleware ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์„ค์น˜
    npm install http-proxy-middleware --save

React App์˜ src ํŒŒ์ผ ์•ˆ์—์„œ setupProxy.js ํŒŒ์ผ์„ ์ƒ์„ฑํ•˜๊ณ , ์•ˆ์—์„œ ์„ค์น˜ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ํŒŒ์ผ์„ ๋ถˆ๋Ÿฌ์˜จ ๋‹ค์Œ, ์•„๋ž˜์™€ ๊ฐ™์ด ์ž‘์„ฑ ํ•œ๋‹ค.

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

module.exports = function(app) {
  app.use(
    '/api', //proxy๊ฐ€ ํ•„์š”ํ•œ path prameter๋ฅผ ์ž…๋ ฅํ•œ๋‹ค.
    createProxyMiddleware({
      target: 'http://localhost:5000', //ํƒ€๊ฒŸ์ด ๋˜๋Š” api url๋ฅผ ์ž…๋ ฅ
      changeOrigin: true, //๋Œ€์ƒ ์„œ๋ฒ„ ๊ตฌ์„ฑ์— ๋”ฐ๋ผ ํ˜ธ์ŠคํŠธ ํ—ค๋”๊ฐ€ ๋ณ€๊ฒฝ๋˜๋„๋ก ์„ค์ •ํ•˜๋Š” ๋ถ€๋ถ„
    })
  );
};

๊ทธ๋ฆฌ๊ณ  ๊ธฐ์กด์˜ fetch๋‚˜ axios๋ฅผ ํ†ตํ•ด ์š”์ฒญ์„ ๋ณด๋‚ด๋˜ ๋ถ€๋ถ„์—์„œ ๋„๋ฉ”์ธ ๋ถ€๋ถ„์„ ์ œ๊ฑฐํ•˜๋ฉด ๋œ๋‹ค.

export async function getAllfetch() {
    const response = await fetch('์šฐํšŒํ•  api์ฃผ์†Œ/params');
    .then(() => {
			...
		})
}

// proxy ์„ค์ • ํ›„
export async function getAllfetch() {
    const response = await fetch('/params');
    .then(() => {
			...
		})
}

// ์—ฌ๋Ÿฌ api ์‚ฌ์šฉ ์‹œ ๋‘ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์ด ์žˆ๋‹ค.

// 1. app.use๋ฅผ ์—ฌ๋Ÿฌ ๋ฒˆ ์ž‘์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•
module.exports = (app) => {
  app.use('/api',
    createProxyMiddleware({
      target: 'http://localhost:3080',
      changeOrigin: true,
    })
  )
  app.use('/api1',
    createProxyMiddleware({
      target: 'http://localhost:3070',
      changeOrigin: true,
    })
  );
};

// 2. router๋ฅผ ํ™œ์šฉํ•ด ์ค‘๋ณต์ž‘์„ฑ์„ ํ•˜์ง€ ์•Š๋Š” ๋ฐฉ๋ฒ•
module.exports = (app) => {
  app.use(
    ['/api','/api2'],
    createProxyMiddleware({
      target: 'http://localhost:3080',
      changeOrigin: true,
      router: {
        '/api2': 'http://localhost:3070'
      }
    })
  );
};

Uploaded by N2T