[๐Ÿ’ป ์ฝ”๋“œ์Šคํ…Œ์ด์ธ  FE 44๊ธฐ]Proxy

JiEunยท2023๋…„ 6์›” 7์ผ
0
post-thumbnail

โœ”๏ธ ์‹œ์ž‘

Proxy, CORS ์—๋Ÿฌ๋ฅผ ํ•ด๊ฒฐ์— ๋Œ€ํ•ด ํ•™์Šตํ•˜๊ณ  ์‹ค์Šต์„ ์ง„ํ–‰ํ–ˆ๋‹ค.


๐Ÿ“ ๋ฐฐ์šด ๊ฒƒ

โœ”๏ธ CORS ์ •์ฑ…์ด ํ•„์š”ํ•œ ์ด์œ 

๋‹ค๋ฅธ ๋„๋ฉ”์ธ์—์„œ API๋ฅผ ์š”์ฒญํ•ด์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด ์ฃผ๋ ค๋ฉด CORS ์„ค์ •์ด ํ•„์š”ํ•˜๋‹ค.

์‹ค์ œ ์„œ๋น„์Šค๊ฐ€ ๋˜๋Š” ์ƒ์šฉ ์•ฑ์„ ์šด์˜ ์ค‘์ธ ๊ฒฝ์šฐ, ๊ตฌ์ถ•ํ•œ ํด๋ผ์ด์–ธํŠธ ๋’ค์˜ ์„œ๋ฒ„์™€ ์—ฐ๊ฒฐ๋˜์–ด ์žˆ๋Š” DB์—๋Š” ๋ผ์ด๋ธŒ ๋ฐ์ดํ„ฐ(live data)๊ฐ€ ์Œ“์ผ ๊ฒƒ์ด๋‹ค.

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

์ฆ‰, ๋ชจ๋“  ๋„๋ฉ”์ธ์„ ํ—ˆ์šฉํ•ด์„œ๋Š” ์•ˆ ๋˜๊ณ , ํŠน์ • ๋„๋ฉ”์ธ์„ ํ—ˆ์šฉํ•˜๋„๋ก ๊ตฌํ˜„ํ•ด์•ผ ํ•œ๋‹ค.

  • ํ”„๋ก ํŠธ์—”๋“œ ๊ฐœ๋ฐœ์ž : ๋ฐฑ์—”๋“œ ๊ฐœ๋ฐœ์ž์—๊ฒŒ ํ”„๋ก ํŠธ์—”๋“œ ๊ฐœ๋ฐœ ์„œ๋ฒ„ ๋„๋ฉ”์ธ์„ ํ—ˆ์šฉํ•ด ๋‹ฌ๋ผ๊ณ  ์š”์ฒญ์„ ํ•ด์•ผ ํ•œ๋‹ค.
  • ๋ฐฑ์—”๋“œ ๊ฐœ๋ฐœ์ž : ์‘๋‹ต ํ—ค๋”์— ํ•„์š”ํ•œ ๊ฐ’๋“ค์„ ๋‹ด์•„์„œ ์ „๋‹ฌ ํ•ด์ค˜์•ผํ•œ๋‹ค.

์„œ๋ฒ„์—์„œ ์ ์ ˆํ•œ ์‘๋‹ต ํ—ค๋”๋ฅผ ๋ฐ›์ง€ ๋ชปํ•˜๋ฉด ๋ธŒ๋ผ์šฐ์ €์—์„œ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

CORS

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

์ถœ์ฒ˜(origin)

  • ์ ‘๊ทผํ•  ๋•Œ ์‚ฌ์šฉํ•˜๋Š” URL์˜ ์Šคํ‚ด(ํ”„๋กœํ† ์ฝœ), ํ˜ธ์ŠคํŠธ(๋„๋ฉ”์ธ), ํฌํŠธ๋กœ ์ •์˜๋œ๋‹ค.
  • ๋‘ ๊ฐ์ฒด์˜ ์Šคํ‚ด, ํ˜ธ์ŠคํŠธ, ํฌํŠธ๊ฐ€ ๋ชจ๋‘ ์ผ์น˜ํ•˜๋Š” ๊ฒฝ์šฐ ๊ฐ™์€ ์ถœ์ฒ˜๋ฅผ ๊ฐ€์กŒ๋‹ค๊ณ  ๋งํ•œ๋‹ค.
  • ์ผ๋ถ€ ์ž‘์—…์€ ๋™์ผ ์ถœ์ฒ˜ ์ฝ˜ํ…์ธ ๋กœ ์ œํ•œ๋˜์ง€๋งŒ, CORS๋ฅผ ํ†ตํ•ด ์ œํ•œ์„ ํ•ด์ œ ํ•  ์ˆ˜ ์žˆ๋‹ค.

๋ผ์ด๋ธŒ ๋ฐ์ดํ„ฐ(live data)

  • ์‹ค์ œ ์„œ๋น„์Šค๋˜๊ณ  ์žˆ๋Š” ์•ฑ์˜ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค(Data Base, DB)์— ์ ์žฌ๋˜๊ณ  ์žˆ๋Š” ๋ฐ์ดํ„ฐ
  • ์œ ์ € ๋ฐ ์ƒํ’ˆ, ๊ฒฐ์ œ ๋“ฑ ๋‹ค์–‘ํ•œ ์ •๋ณด๋“ค์„ ์˜ˆ๋กœ ๋“ค ์ˆ˜ ์žˆ๋‹ค.

โœ”๏ธ Proxy

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

[proxy ์ ์šฉ ์ „ ํ๋ฆ„.png]

[proxy ์ ์šฉ ์ „ ํ๋ฆ„.png]์„ ๋ณด๋ฉด proxy๋ฅผ ์ ์šฉํ•ด ๋ธŒ๋ผ์šฐ์ €๋ฅผ ์†์ด๊ธฐ ์ „ ํ๋ฆ„์ด๋‹ค.

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

[proxy ์ ์šฉ ํ›„ ํ๋ฆ„.png]

[proxy ์ ์šฉ ํ›„ ํ๋ฆ„.png]๋ฅผ ๋ณด๋ฉด proxy๋ฅผ ์ ์šฉํ•ด ๋ธŒ๋ผ์šฐ์ €๋ฅผ ์†์ธ ํ›„ ํ๋ฆ„์ด๋‹ค.

  • React ์•ฑ์—์„œ ๋ธŒ๋ผ์šฐ์ €๋ฅผ ํ†ตํ•ด API๋ฅผ ์š”์ฒญํ•  ๋•Œ Proxy๋ฅผ ํ†ตํ•ด ๋ฐฑ์—”๋“œ ์„œ๋ฒ„๋กœ ์š”์ฒญ์„ ์šฐํšŒํ•ด ๋ณด๋‚ด๊ฒŒ ๋œ๋‹ค.
  • ๋ฐฑ์—”๋“œ ์„œ๋ฒ„๋Š” ์‘๋‹ต์„ React ์•ฑ์œผ๋กœ ๋ณด๋‚ธ๋‹ค.
  • React ์•ฑ์€ ๋ฐ›์€ ์‘๋‹ต์„ ๋ฐฑ์—”๋“œ ์„œ๋ฒ„ ๋Œ€์‹  ๋ธŒ๋ผ์šฐ์ €์—๊ฒŒ ์ „๋‹ฌํ•œ๋‹ค.

์ด๋Ÿฐ ๊ฒฝ์šฐ ์ถœ์ฒ˜๊ฐ€ ๊ฐ™์•„์ง€๊ธฐ ๋•Œ๋ฌธ์— ๋ธŒ๋ผ์šฐ์ €๋Š” ์ด ์‚ฌ์‹ค์„ ๋ˆˆ์น˜์ฑ„์ง€ ๋ชปํ•˜๊ณ  ํ—ˆ์šฉํ•˜๊ฒŒ ๋œ๋‹ค.

โœ”๏ธ Proxy ์‚ฌ์šฉ๋ฒ•

- webpack dev server proxy

webpack dev server์—์„œ ์ œ๊ณตํ•˜๋Š” proxy ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ๋‹ค.

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

์›นํŒฉ ๊ฐœ๋ฐœ์„œ๋ฒ„์˜ proxy ์„ค์ •์€ ์›๋ž˜ ์›นํŒฉ ์„ค์ •์„ ํ†ตํ•ด์„œ ์ ์šฉ์„ ํ•˜์ง€๋งŒ, CRA๋ฅผ ํ†ตํ•ด ๋งŒ๋“  ๋ฆฌ์•กํŠธ ํ”„๋กœ์ ํŠธ์—์„œ๋Š” package.json ์—์„œ "proxy" ๊ฐ’์„ ์„ค์ •ํ•ด ์‰ฝ๊ฒŒ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ๊ตฌ์„ฑ ๋˜์–ด ์žˆ๋‹ค.

...
"browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  },
    //proxy๋Š” ๋ณดํ†ต ๋งจ ๋ฐ‘์— ์ž‘์„ฑ์„ ํ•ด ๊ธˆ๋ฐฉ ์ฐพ์„ ์ˆ˜ ์žˆ๋„๋ก ํ•œ๋‹ค.
	"proxy" : "์šฐํšŒํ•  API ์ฃผ์†Œ"
}
  • proxy๋Š” ๋ณดํ†ต ๋งจ ๋ฐ‘์— ์ž‘์„ฑ์„ ํ•ด ๊ธˆ๋ฐฉ ์ฐพ์„ ์ˆ˜ ์žˆ๋„๋ก ํ•œ๋‹ค.
//๊ธฐ์กด์˜ fetch, ํ˜น์€ axios๋ฅผ ํ†ตํ•ด ์š”์ฒญํ•˜๋˜ ๋ถ€๋ถ„์—์„œ ๋„๋ฉ”์ธ ๋ถ€๋ถ„์„ ์ œ๊ฑฐ
export async function getAllfetch() {

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

    const response = await fetch('/params');
    .then(() => {
			...
		})
}
  • ๊ธฐ์กด์˜ fetch, ํ˜น์€ axios๋ฅผ ํ†ตํ•ด ์š”์ฒญํ•˜๋˜ ๋ถ€๋ถ„์—์„œ ๋„๋ฉ”์ธ ๋ถ€๋ถ„์„ ์ œ๊ฑฐํ•œ๋‹ค.

- React Proxy ์‚ฌ์šฉ๋ฒ•

webpack dev server์—์„œ ์ œ๊ณตํ•˜๋Š” proxy๋Š” ์ „์—ญ์ ์ธ ์„ค์ •์ด๊ธฐ ๋•Œ๋ฌธ์—, ์ข…์ข… ํ•ด๋‹น ๋ฐฉ๋ฒ•์ด ์ถฉ๋ถ„ํžˆ ์ ์šฉ๋˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ๊ฐ€ ์ƒ๊ธฐ๊ธฐ๋„ ํ•œ๋‹ค.

๊ทธ๋Ÿฐ ๊ฒฝ์šฐ ์ˆ˜๋™์œผ๋กœ proxy๋ฅผ ์ ์šฉํ•ด์ค˜์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ๋‹ค.
(http-proxy-middleware ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉ)

npm install http-proxy-middleware --save
  • http-proxy-middleware ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์„ค์น˜
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๋ฅผ ํ†ตํ•ด ์š”์ฒญํ•˜๋˜ ๋ถ€๋ถ„์—์„œ ๋„๋ฉ”์ธ ๋ถ€๋ถ„์„ ์ œ๊ฑฐํ•œ๋‹ค.
  • ๋ฐ‘์˜ ๋ถ€๋ถ„์€ webpack dev server์—์„œ ์ œ๊ณตํ•˜๋Š” proxy ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•  ๋•Œ์™€ ๋™์ผํ•˜๋‹ค.

๊ณผ์ œ ์ง„ํ–‰

webpack dev server proxy, React Proxy ๋‘ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์œผ๋กœ ์‹ค์Šต์„ ์ง„ํ–‰ํ–ˆ๋‹ค.

webpack dev server proxy์€ ๊ธฐ์กด ๋ฐฐ์› ๋˜ ๋‚ด์šฉ๊ณผ ๋™์ผํ–ˆ๋‹ค.
React Proxy๋Š” client์—์„œ ์ž‘์—…ํ•ด ์ฃผ๋ฉด๋œ๋‹ค.

2๊ฐ€์ง€ ์„œ๋ฒ„์™€ ์—ฐ๊ฒฐ๋˜์–ด์•ผ ํ•ด์„œ ์ด๋ถ€๋ถ„์„ ์–ด๋–ป๊ฒŒ ์ž‘์„ฑํ•ด์•ผ ํ•˜๋Š”์ง€ ํ—ค๋งธ์—ˆ๋‹ค.

์ •๋ง ๋‹จ์ˆœํ•˜๊ฒŒ ๋™์ผํ•˜๊ฒŒ ์ž‘์„ฑ ํ•ด ๊ฒฝ๋กœ, ๋„๋ฉ”์ธ ๋ถ€๋ถ„๋งŒ ๋ณ€๊ฒฝํ•ด ์ฃผ๋ฉด๋œ๋‹ค.

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

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

  app.use(
    '/api2', 
    createProxyMiddleware({
      target: 'http://localhost:3070', 
      changeOrigin: true, 
    })
  );
};

์ดํ›„ ์ปดํฌ๋„ŒํŠธ ์ž‘์—… ํ›„ ์„œ๋ฒ„๋ฅผ api, api2๊ฒฝ๋กœ๋กœ ๊ฐ€์„œ
npm run dev๋กœ ์‹คํ–‰ํ•ด ์ฃผ๋ฉด ๋œ๋‹ค.

http://localhost:3080์˜ books์™€
http://localhost:3070์˜ todos๊ฐ€ ์ž˜ ๋‚˜์˜ค๋Š” ๊ฑธ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

(์ค‘๊ฐ„ ์ค‘๊ฐ„ ๋‚ด์šฉ์€ ํ…Œ์ŠคํŠธ ํ•˜๋Š๋ผ... ์ €๋ ‡๊ฒŒ ๋๋‹ค)


โœ๏ธ ๋งˆ์น˜๋ฉฐ

CORS ์—๋Ÿฌ๋ฅผ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ํ•™์Šตํ•˜๊ณ  ์‹ค์Šตํ•˜๋Š” ์‹œ๊ฐ„์„ ๊ฐ€์กŒ๋‹ค.

์™œ proxy๋ฅผ ์‚ฌ์šฉํ•ด์•ผํ•˜๊ณ  ์–ด๋–ค์‹์œผ๋กœ ์ž‘์„ฑ์„ ํ•ด์•ผํ•˜๋Š”์ง€ ์•Œ ์ˆ˜ ์žˆ์—ˆ๋‹ค.

๊ธ€๋กœ ๊ณต๋ถ€ํ•œ๋Š”๊ฑฐ ๋ณด๋‹ค ์‹ค์Šต์„ ํ†ตํ•ด ์ง„ํ–‰ํ•˜๋‹ˆ ๋” ์ž˜ ์ดํ•ด ํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค.

profile
๐Ÿ’ป ํ”„๋ก ํŠธ์—”๋“œ๋ฅผ ๋ชฉํ‘œ๋กœ ์„ฑ์žฅ ์ค‘! (์•Œ์•„๋ดค๋˜ ๋‚ด์šฉ ๋“ฑ์„ ์ •๋ฆฌํ•˜๊ธฐ)

0๊ฐœ์˜ ๋Œ“๊ธ€