๐ฌ ์ง๋๊ธ๋ค๊ณผ ๋ง์ฐฌ๊ฐ์ง๋ก ์ด๋ฒ์๋ ์ญ์ CodeStates ๋ถํธ์บ ํ ์ค ์ค์ตํ๋ ๋ด์ฉ์ผ๋ก Proxy ์ค์ ์ ๊ดํ ๋ถ๋ถ์ด๋ค.
Proxy ์๋ฒ, ์ธ์ ์ฌ์ฉํ ์ ์์๊น?
๋ธ๋ผ์ฐ์ ์์ ๊ธฐ๋ณธ์ ์ผ๋ก API๋ฅผ ์์ฒญ ํ ๋์๋ ๋ธ๋ผ์ฐ์ ์ ํ์ฌ ์ฃผ์์ API ์ฃผ์์ ๋๋ฉ์ธ์ด ์ผ์นํด์ผ๋ง ๋ฐ์ดํฐ์ ์ ๊ทผ ํ ์ ์๋ค. ๋ง์ฝ ๋ค๋ฅธ ๋๋ฉ์ธ์์ API๋ฅผ ์์ฒญํด์ ์ฌ์ฉ ํ ์ ์๊ฒ ํด์ฃผ๋ ค๋ฉด CORS ์ค์ ์ด ํ์ํ๋ค.
๐ฉ๐ป๐ป ์ค์ ์๋น์ค๋ฅผ ๊ฐ๋ฐํ๋ฉฐ ์๋ฒ์ API ๋ฅผ ์์ฒญํด์ผ ํ ๋, ๊ธฐ๋ณธ์ ์ผ๋ก๋ localhost:3000
์์ ๋ค์ด์ค๋ ๊ฒ์ด ์ฐจ๋จ๋๊ธฐ ๋๋ฌธ์ ์๋ฒ ์ชฝ์ ํด๋น ๋๋ฉ์ธ์ ํ์ฉํ๋๋ก ๊ตฌํ์ ํด์ผํ๋ค. ํ์ง๋ง CORS ์ค์ ์ ํ๋ ๋ฐฑ์๋ ๊ฐ๋ฐ์๊ฐ ๋ฐ์๊ฑฐ๋, ๊ธฐ๋ฅ ๊ตฌํ์ด ๋น์ฅ์ ์๋๋ค๋ฉด? ์๋ฒ์์ ๋ฟ๋ง ์๋๋ผ ํด๋ผ์ด์ธํธ์ ์นํฉ ๊ฐ๋ฐ์๋ฒ(๋๋ React ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋ฑ)์์ ์ ๊ณตํ๋ Proxy๋ผ๋ ๊ธฐ๋ฅ์ ์ฌ์ฉํด์๋ CORS ์ ์ฑ
์ ์ฐํํ ์ ์๋ค.
์ด๋ ๋ณ๋์ ์๋ต ํค๋๋ฅผ ๋ฐ์ ํ์ ์์ด ๋ธ๋ผ์ฐ์ ๋ React ์ฑ์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ์์ฒญํ๊ณ , ํด๋น ์์ฒญ์ ๋ฐฑ์๋๋ก ์ ๋ฌํ๊ฒ ๋๋ค. ์ฌ๊ธฐ์ React ์ฑ์ด ์๋ฒ๋ก๋ถํฐ ๋ฐ์ ์๋ต ๋ฐ์ดํฐ๋ฅผ ๋ค์ ๋ธ๋ผ์ฐ์ ๋ก ์ ๋ฌํ๋ ๋ฐฉ๋ฒ์ ์ฐ๊ธฐ ๋๋ฌธ์ ๋ธ๋ผ์ฐ์ ๋ CORS ์ ์ฑ ์ ์๋ฐํ๋์ง ๋ชจ๋ฅด๊ฒ ๋๋ค. ๋ธ๋ผ์ฐ์ ๋ฅผ proxy ๊ธฐ๋ฅ์ ํตํด ์์ด๋ ๊ฒ์ด๋ค.
1. webpack dev server์ proxy
๐ฉ๐ป๐ป webpack dev server์ proxy ๊ธฐ๋ฅ์ ์ฌ์ฉํด ์ฐํํ์ฌ ์๋ต ๋ฐ๊ธฐ
webpack dev server์ proxy๋ฅผ ์ฌ์ฉํ๊ฒ ๋๋ฉด, ๋ธ๋ผ์ฐ์ API๋ฅผ ์์ฒญํ ๋ ๋ฐฑ์๋ ์๋ฒ์ ์ง์ ์ ์ผ๋ก ์์ฒญ์ ํ์ง ์๊ณ , ํ์ฌ ๊ฐ๋ฐ์๋ฒ์ ์ฃผ์๋ก ์ฐํ ์์ฒญ์ ํ๊ฒ ๋๋ค. ๊ทธ๋ฌ๋ฉด ์นํฉ ๊ฐ๋ฐ ์๋ฒ์์ ํด๋น ์์ฒญ์ ๋ฐ์ ๊ทธ๋๋ก ๋ฐฑ์๋ ์๋ฒ๋ก ์ ๋ฌํ๊ณ , ๋ฐฑ์๋ ์๋ฒ์์ ์๋ตํ ๋ด์ฉ์ ๋ค์ ๋ธ๋ผ์ฐ์ ์ชฝ์ผ๋ก ๋ฐํํ๋ค.
1) proxy ์ถ๊ฐ
์นํฉ ๊ฐ๋ฐ์๋ฒ์ 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" : "<http://localhost:3080>" // ์ฐํํ IP ์ฃผ์
}
๐ฌ proxy๋ ๋ณดํต ๋งจ ๋ฐ์ ์์ฑ์ ํด ๊ธ๋ฐฉ ์ฐพ์ ์ ์๋๋ก ํ๋ค.
2) ์์ฒญ url์ ๋๋ฉ์ธ ๋ถ๋ถ ์ ๊ฑฐ
fetch, ํน์ axios๋ฅผ ํตํด ์์ฒญํ๋ ๋ถ๋ถ์์ ๋๋ฉ์ธ ๋ถ๋ถ์ ์ ๊ฑฐํ๋ค.
export async function getAllfetch() {
const response = await fetch('์ฐํํ api์ฃผ์/params');
.then(() => {
...
})
}
โฌ๏ธ
export async function getAllfetch() {
const response = await fetch('/params');
.then(() => {
...
})
}
example
โ๏ธ CodeStates SEB ๊ณผ์ ์ค ์์ ์ฝ๋
// BookService.js
/* ๊ธฐ์กด fetch url์ ๋๋ฉ์ธ ๋ถ๋ถ์ ์ ๊ฑฐํ๋ค.
const response = await fetch('<http://localhost:3080/api/books>');
*/
export const getAllBooks = async () => {
const response = await **fetch('/api/books')**;
return await response.json();
}
export const createBook = async (data) => {
const response = await **fetch('/api/book'**, {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({book: data})
})
return await response.json();
}
โ๏ธ proxy ์ค์ ์ ๊ฑด๋๋ฆฌ๋ฉด ํด๋ผ์ด์ธํธ๋ฅผ ๋ค์ ์์ํด์ค์ผ ํ๋ค๊ณ ํ๋ค.
Uncaught (in promise) SyntaxError: Unexpected token '<', "<!DOCTYPE "... is not valid JSON
โ๏ธ CodeStates SEB ๊ณผ์ ์ค , ์ฒ์ proxy ์ค์ ํ์ ์์ ๊ฐ์ ์๋ฌ๊ฐ ๊ณ์ํด์ ๋ฌ๋ค. npm start
๋ก ํด๋ผ์ด์ธํธ๋ฅผ ๋ค์ ์์ํ๋ ์ ์ฉ์ด ๋์๋ค. ๋์ ๊ฐ์ ์๋ฌ๊ฐ ๋ ์ฌ๋์ด ๋ช๋ช ์๋๊ฒ ๊ฐ์๋๋ฐ, ํด๊ฒฐ์ด ์๋ ๋ถ๋ค๋ ์๋ ๊ฒ ๊ฐ๋ค. ์ด๋ ๋คํธ์ํฌ ๋ฌธ์ ์ผ ์ ์๋ค๊ณ ํ๋ค.
2. React Proxy ์ฌ์ฉ๋ฒ
๐ฉ๐ป๐ป http-proxy-middleware์ proxy ๊ธฐ๋ฅ์ ์ฌ์ฉํ์ฌ 2๊ฐ ์ด์์ ๋๋ฉ์ธ์์ ์๋ต ๋ฐ๊ธฐ
webpack dev server์์ ์ ๊ณตํ๋ proxy๋ ์ ์ญ์ ์ธ ์ค์ ์ด๊ธฐ ๋๋ฌธ์, ์ข
์ข
ํด๋น ๋ฐฉ๋ฒ์ด ์ถฉ๋ถํ ์ ์ฉ๋์ง ์๋ ๊ฒฝ์ฐ๊ฐ ์๊ธฐ๊ธฐ๋ ํ๋ค. ๊ทธ๋์ ์๋์ผ๋ก proxy๋ฅผ ์ ์ฉํด์ค์ผ ํ๋ ๊ฒฝ์ฐ๊ฐ ์๋๋ฐ, ์ด๋๋ http-proxy-middleware
๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํด์ผ ํ๋ค.
1) http-proxy-middleware ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ค์น
npm install http-proxy-middleware --save
2) src ํด๋ ๋ด setupProxy.js ํ์ผ ์์ฑ
โจ ๊ธฐ๋ณธ์์
// 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, // ๋์ ์๋ฒ ๊ตฌ์ฑ์ ๋ฐ๋ผ ํธ์คํธ ํค๋๊ฐ ๋ณ๊ฒฝ๋๋๋ก ์ค์ ํ๋ ๋ถ๋ถ
})
);
};
โจ ๋ ๊ฐ ์ด์์ ๋๋ฉ์ธ ์ค์
// setupProxy.js
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,
})
);
};
// ์์ฒ๋ผ ๋ฐ๋ก ์์ฑํ์ง ์๊ณ , ํ๋ฒ์ ์จ์ค์๋ ์๋ค.
module.exports = function(app) {
app.use(
['/api', '/api2'],
createProxyMiddleware({
target: '<http://localhost:3080>', // ๊ธฐ๋ณธ url (๋ฐฐ์ด ๋งจ ์ api์ ์ฃผ์)
changeOrigin: true,
router: {
'/api2' : '<http://localhost:3070>'
}
})
);
};
3) ์์ฒญ url์ ๋๋ฉ์ธ ๋ถ๋ถ ์ ๊ฑฐ
fetch, ํน์ axios๋ฅผ ํตํด ์์ฒญํ๋ ๋ถ๋ถ์์ ๋๋ฉ์ธ ๋ถ๋ถ์ ์ ๊ฑฐํ๋ค.
(webpack dev server์์ ์ ๊ณตํ๋ proxy ๊ธฐ๋ฅ์ ์ฌ์ฉํ ๋์ ๋์ผ)
export async function getAllfetch() {
const response = await fetch('์ฐํํ api์ฃผ์/params');
.then(() => {
...
})
}
export async function getAllfetch() {
const response = await fetch('/params');
.then(() => {
...
})
}
example
โ๏ธ CodeStates SEB ๊ณผ์ ์ค ์์ ์ฝ๋
// setupProxy.js
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,
})
);
};
export const getAllTodos = async () => {
const response = await **fetch('/api2/todos')**;
return await response.json();
}
export const createTodo = async (data) => {
const response = await **fetch('/api2/todo'**, {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({todo: data})
})
return await response.json();
}
โ๏ธ ์ด๋ ๊ฒ ํ๋ฉด ์๋ก ๋ค๋ฅธ ๋๋ฉ์ธ์์๋ ๋ฐ์ดํฐ๋ฅผ ๋ฐ์์ฌ ์ ์๋ค.
'Frontend Dev > ๊ธฐํ ์ค์ต' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
Github Actions, AWS S3๋ฅผ ์ฌ์ฉํ CI/CD (0) | 2023.08.01 |
---|---|
mkcert ์ฌ์ฉ๋ฒ - ๋ก์ปฌ ๊ฐ๋ฐ์ ์ํ HTTPS ํ๊ฒฝ ๋ง๋ค๊ธฐ (0) | 2023.06.30 |