์ด๋ฒ์๋ node.js
์ http
๋ชจ๋์ ์ด์ฉํ์ฌ ์น ์๋ฒ๋ฅผ ๋ง๋ค์ด๋ดค๋ค. ์์ ํ์ผ์ ์ฝ๊ฑฐ๋ ์ฐ๊ธฐ ์ํ fs
๋ชจ๋์ ์ฌ์ฉํด๋ณธ์ ์ด ์์๋๋ฐ http
๋ชจ๋์ HTTP
์์ฒญ, ์๋ต์ ๋ค๋ฃฌ๋ค. HTTP
์ง์์ด ์ ํ๋์ด์ผ ํ๊ธฐ ๋๋ฌธ์ ๋จผ์ HTTP
ํธ๋์ญ์
ํด๋ถ๋ผ๋ ๊ณต์ ๊ฐ์ด๋ ๋ฌธ์๋ฅผ ๊ณต๋ถํ๋ค.
node.js
HTTP
์ฒ๋ฆฌ ๊ณผ์ ์ ์ด ๋ฌธ์๋ฅผ ํตํด ์ดํดํด๋ณด์.
๋ชจ๋ node
์น ์๋ฒ ์ ํ๋ฆฌ์ผ์ด์
์ ์น ์๋ฒ ๊ฐ์ฒด๋ฅผ ๋ง๋ค์ด์ผ ํ๋ค. ์ด ๋ createServer
๋ฅผ ์ด์ฉํ๋ค.
const http = require('http');
const server = http.createServer((request, response) => {
// ์ฌ๊ธฐ์ ์์
์ด ์งํ๋ฉ๋๋ค!
});
์ด ์๋ฒ๋ก ์ค๋ HTTP
์์ฒญ๋ง๋ค createServer
์ ์ ๋ฌ๋ ํจ์๊ฐ ํ ๋ฒ์ฉ ํธ์ถ๋๋ค. HTTP
์์ฒญ์ด ์๋ฒ์ ์ค๋ฉด node
๊ฐ ํธ๋์ญ์
์ ๋ค๋ฃจ๋ ค๊ณ request
์ response
๊ฐ์ฒด๋ฅผ ์ ๋ฌํ๋ฉฐ ์์ฒญ ํธ๋ค๋ฌ ํจ์๋ฅผ ํธ์ถํ๋ค. ์์ฒญ์ ์ค์ ๋ก ์ฒ๋ฆฌํ๋ ค๋ฉด listen
๋ฉ์๋๊ฐ server
๊ฐ์ฒด์์ ํธ์ถ๋์ด์ผ ํ๋ค. ๋๋ถ๋ถ์ ์๋ฒ๊ฐ ์ฌ์ฉํ๊ณ ์ ํ๋ ํฌํธ ๋ฒํธ๋ฅผ listen
์ ์ ๋ฌํ๊ธฐ๋ง ํ๋ฉด ๋๋ค.
์์ฒญ์ ์ฒ๋ฆฌํ ๋, ์ฐ์ ๋ฉ์๋์ URL
์ ํ์ธํ ํ ์ด์ ๊ด๋ จ๋ ์ ์ ํ ์์
์ ์คํํด์ผํ๋ค. node
๋ request
๊ฐ์ฒด์ ๊ฐ ํ๋กํผํฐ๋ฅผ ๋ฃ์ด๋์์ผ๋ฏ๋ก ์ฝ๊ฒ ์์
๊ฐ๋ฅํ๋ค.
const { method, url } = request;
const { headers } = request;
const userAgent = headers['user-agent'];
์ฌ๊ธฐ์ method
๋ ์ผ๋ฐ์ ์ธ HTTP
๋ฉ์๋/๋์ฌ๊ฐ ๋ ๊ฒ์ด๊ณ , url
์ ์ ์ฒด URL
์์ ์๋ฒ, ํ๋กํ ์ฝ, ํฌํธ๋ฅผ ์ ์ธํ ๊ฒ์ผ๋ก, ์ธ ๋ฒ์งธ ์ฌ๋์ ์ดํ์ ๋๋จธ์ง ์ ๋ถ์ด๋ค.
request
์ headers
๋ผ๋ ์ ์ฉ ๊ฐ์ฒด๊ฐ ์๊ณ , ํด๋ผ์ด์ธํธ๊ฐ ์ด๋ป๊ฒ ํค๋๋ฅผ ์ค์ ํ๋์ง์ ๊ด๊ณ์์ด ๋ชจ๋ ํค๋๋ ์๋ฌธ์๋ก๋ง ํํ๋๋ค๋ ๊ฒ์ ๊ธฐ์ตํ์. ์ด๋ ์ด๋ค ๋ชฉ์ ์ด๋ ํค๋๋ฅผ ํ์ฑํ๋ ์์
์ ๊ฐํธํ๊ฒ ํด์ค๋ค.
POST
๋ PUT
์์ฒญ์ ๋ฐ์ ๋ ์ ํ๋ฆฌ์ผ์ด์
์ ์์ฒญ ๋ฐ๋๋ ์ค์ํ ๊ฒ์ด๋ค. ํธ๋ค๋ฌ์ ์ ๋ฌ๋ request
๊ฐ์ฒด๋ ReadableStream
์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ๊ณ ์๋๋ฐ, ์ด ์คํธ๋ฆผ์ 'data'
์ 'end'
์ด๋ฒคํธ์ ์ด๋ฒคํธ ๋ฆฌ์ค๋๋ฅผ ๋ฑ๋กํด์ ๋ฐ์ดํฐ๋ฅผ ๋ฐ์ ์ ์๋ค.
๊ฐ 'data'
์ด๋ฒคํธ์์ ๋ฐ์์ํจ ์ฒญํฌ๋ Buffer
์ด๋ค. ์ด ์ฒญํฌ๋ ๋ฌธ์์ด ๋ฐ์ดํฐ์ด๋ฏ๋ก ์ด ๋ฐ์ดํฐ๋ฅผ ๋ฐฐ์ด์ ๋ด๊ณ , 'end'
์ด๋ฒคํธ์์ ์ด์ด ๋ถ์ธ ๋ค์ ๋ฌธ์์ด๋ก ๋ง๋๋ ๊ฒ์ด ๊ฐ์ฅ ์ข๋ค.
let body = [];
request.on('data', (chunk) => {
body.push(chunk);
}).on('end', () => {
body = Buffer.concat(body).toString();
// ์ฌ๊ธฐ์ `body`์ ์ ์ฒด ์์ฒญ ๋ฐ๋๊ฐ ๋ฌธ์์ด๋ก ๋ด๊ฒจ์์ต๋๋ค.
});
์ด๋ฒ์ ๋ง๋ค์ด์ผํ ์น ์๋ฒ์ ๊ธฐ๋ฅ์ ๋งค์ฐ ๋จ์ํ๋ค. ๋ฒํผ์ ํด๋ฆญํจ์ ๋ฐ๋ผ ๊ฐ๊ธฐ ๋ค๋ฅธ ์์ฒญ์ ๋ณด๋ด๋ฉฐ, ๊ฐ๊ฐ ๋ณด๋ธ ๋จ์ด๋ฅผ ์๋ฌธ์ ๋๋ ๋๋ฌธ์๋ก ๋ฐ๊พธ๋ฉด ๋๋ ๊ฒ์ด์๋ค.
URL
์ด /lower
์ด๊ณ , POST
์์ฒญ์ด ์๋ค๋ฉด ์๋ฒ๋ ๋ฌธ์์ด์ ์๋ฌธ์๋ก ๋ง๋ค์ด ์๋ตํด์ผ ํ๊ณ , URL
์ด /upper
์ธ POST
์์ฒญ์๋ ๋ฌธ์์ด์ ๋๋ฌธ์๋ก ๋ง๋ค์ด ์๋ตํด์ผ ํ๋ค. ๋ํ, CORS
๊ด๋ จ ํค๋๋ฅผ OPTIONS
์๋ต์ ์ ์ฉํด์ผ ํ๋ค.
๋ฐ๋ผ์, ๋จผ์ Method
๊ฐ POST
์ธ์ง OPTIONS
์ธ์ง ๋ถ๊ธฐํ๊ณ , POST
์์ฒญ์ด ์๋ค๋ฉด URL
์ ํ์ธํ๊ณ ์๋ง์ ์์ฒญ์ ๋ณด๋ด์ฃผ๋ ์์ผ๋ก ๊ตฌํํ๋ค.
const http = require('http');
const PORT = 5000;
const ip = 'localhost';
const server = http.createServer((request, response) => {
if (request.method === 'OPTIONS') {
// ํด๋ผ์ด์ธํธ์ preflight request์ ๋ํ ์๋ต์ ๋๋ ค์ค๋ค
response.writeHead(200, defaultCorsHeader);
response.end();
}
if (request.method === 'POST') {
let body = [];
request
.on('data', (chunk) => {
// ์์ HTTP ํธ๋์ญ์
ํด๋ถ ๋ฌธ์์์ ๊ณต๋ถํ๋ ๊ฒ์ฒ๋ผ,
// body ๋ฐฐ์ด์ chunk๋ฅผ ๋ด๊ณ
body.push(chunk);
})
.on('end', () => {
// end ์ด๋ฒคํธ์์ ์ด์ด ๋ถ์ด๊ณ ๋ฌธ์์ด๋ก ๋ง๋ ๋ค
body = Buffer.concat(body).toString();
response.writeHead(201, defaultCorsHeader);
if (request.url === '/lower') {
response.end(body.toLowerCase());
} else if (request.url === '/upper') {
response.end(body.toUpperCase());
} else {
response.writeHead(404, defaultCorsHeader);
response.end();
}
});
}
});
server.listen(PORT, ip, () => {
console.log(`http server listen on ${ip}:${PORT}`);
});
// ์๋ต ํค๋
const defaultCorsHeader = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type, Accept',
'Access-Control-Max-Age': 10,
};
์ด ์ฝ๋๋ ์ ์ด์ ๋ฌธ์์ด ๋ณ์ data
๋ฅผ ์ ์ธํ์ฌ 'data'
์ด๋ฒคํธ์์ chunk
๋ฅผ ๋ํด์ฃผ๊ณ , 'end'
์ด๋ฒคํธ์์ ๊ทธ data
๋ฅผ ์๋ฌธ์ ํน์ ๋๋ฌธ์๋ก ๋ฐ๊พธ์ด ์๋ตํ๋ ํํ์ ์ฝ๋์ด๋ค. ํจ์ฌ ๊ฐ๋จํ๊ฒ ๊ตฌํํ ๋ชจ์ต์ด๋ค.
const http = require('http');
const PORT = 5000;
const ip = 'localhost';
const server = http.createServer((req, res) => {
if (req.method === 'POST') {
if (req.url === '/lower') {
let data = '';
req.on('data', chunk => {
data = data + chunk;
});
req.on('end', () => {
data = data.toLowerCase();
res.writeHead(201, defaultCorsHeader);
res.end(data);
});
} else if (req.url === '/upper') {
let data = '';
req.on('data', chunk => {
data = data + chunk;
});
req.on('end', () => {
data = data.toUpperCase();
res.writeHead(201, defaultCorsHeader);
res.end(data);
});
} else {
res.writeHead(404, defaultCorsHeader);
res.end();
}
}
if (req.method === 'OPTIONS') {
res.writeHead(200, defaultCorsHeader);
res.end();
}
});
server.listen(PORT, ip, () => {
console.log(`http server listen on ${ip}:${PORT}`);
});
const defaultCorsHeader = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type, Accept',
'Access-Control-Max-Age': 10
};
์ ๋์ํ๋ ๋ชจ์ต์ด๋ค. ์ฒ์์ผ๋ก ์๋ฒ๋ฅผ ์ง์ ๋ง๋ค์ด๋ณด๋ ์คํ๋ฆฐํธ์๋ค. ๊ฐ์๊ธฐ ๊ณต๋ถ์ ๋์ด๋๊ฐ ๊ธ๊ฒฉํ๊ฒ ์ด๋ ค์์ง ๋๋์ด์๋ค. HTTP
๋ ๋ฌด์์ธ์ง, API
๋ ๋ฌด์์ธ์ง, CORS
๋ ๋ ๋ญ์ง... ํ๋์ฉ ์ดํดํ๋๋ฐ๋ ๋ฒ
์ฐฌ ๋๋์ด์๋ค.
ํ์ง๋ง ์ญ์ ๊ณต๋ถํ๋ฉด ๋๋ค. ์ฐจ๊ทผ์ฐจ๊ทผ ์์๊ฐ๊ณ ๊ฒ์ํด๋ณด๊ณ , ๊ณต์ ๋ฌธ์์ ๋ด์ฉ๋ค์ ๊ณ์ ๋ฐ๋ผํด๋ณด๊ณ ์ฝ์์ ์ถ๋ ฅํด๋ณด๋ฉด์ ํด๋ผ์ด์ธํธ์ HTTP
์์ฒญ๊ณผ ์๋ฒ์ HTTP
์๋ต์ด ์ด๋ค์์ผ๋ก ์ด๋ฃจ์ด์ก๊ณ , ์ด๋ป๊ฒ ์ฌ์ฉํ๋ฉด ๋ ์ง ๊ฐ์ ์ก์ ์ ์๋ ์คํ๋ฆฐํธ์๋ค.
๋ด๊ฐ ์ง์ ์๋ฒ๋ฅผ ๋ง๋ค๋ค๋... ๋๋ฌด ์ฌ๋ฐ์๋ค. ์์ง ๋ชจ๋ฅด๋๊ฒ ์ ๋ง ๋ง๋ค. ํ ๊ฒ ๋ง๋ค๊ณ ๋๊ปด์ง๋๊ฑด ๋ด๊ฐ ๋ฌด์์ ํด์ผํ๋์ง ์ ํํ ์๊ณ ์๋ค๋ ๋ป์ด๋๋ค. ์ด ๋ชจ๋ ๊ณผ์ ์ด ๊ณต๋ถ๋ผ๊ณ ์๊ฐํ๊ณ , ๊ทธ๋ ๊ฒ ๋๊ปด์ง๋ค.
๋ค์์ฃผ๋ถํฐ๋ ChatterBox Client
์คํ๋ฆฐํธ์ ์๋ฒ๋ฅผ ์ง์ ๋ง๋ค์ด๋ณธ๋ค. ๋ฒ์จ๋ถํฐ ๊ธฐ๋๊ฐ ๋๋ค.