내일 배움 캠프/그땐 (응답하라 추억시대)
Node.js TCP서버에서 query와 params를 이용하여 CRUD 하기
verdantjuly
2023. 8. 19. 17:56
728x90
방법
query
1. 파싱한 uri에서 uri.query를 변수에 담아 파라미터로 보내 진행한다.
2. TCP server에서 받은 패킷 안에서 정보를 빼내온다.
params
/users/1 로 접속을 허용하면서 값을 가져와야 한다고 가정하자.
1. localhost:8000으로 들어와서 Gateway를 지나기 전에 pathname을 split를 통해 가공한다. > /users 까지만 나오게
2. 뒤따라오는 params부분을 body의 JSON을 담은 객체 안에 넣어준다.
3. TCP server에서 받은 패킷 안에서 정보를 빼내온다.
app.js
import http from 'http';
import url from 'url';
import dotenv from 'dotenv';
import TcpClient from './classes/client';
import { makePacket } from './utils/makePacket';
dotenv.config();
const port = process.env.GATE_PORT;
let mapClients = {};
let mapUrls = {};
let mapResponse = {};
let mapRR = {};
let index = 0;
const server = http
.createServer((req, res) => {
const method = req.method;
const uri = url.parse(req.url, true);
const pathname = uri.pathname;
if (method === 'POST') {
let body = '';
req.on('data', function (data) {
body += data;
});
req.on('end', function () {
let params;
if (req.headers['content-type'] === 'application/json') {
params = JSON.parse(body);
}
onRequest(res, method, pathname, params);
});
} else if (method === 'DELETE' || method === 'PATCH') {
let body = '';
req.on('data', function (data) {
body += data;
});
req.on('end', function () {
let params;
if (req.headers['content-type'] === 'application/json') {
params = JSON.parse(body);
}
const path = '/' + pathname.split('/')[1];
if (params) {
params.params = pathname.split('/')[2];
} else {
params = { params: pathname.split('/')[2] };
}
onRequest(res, method, path, params);
});
} else {
onRequest(res, method, pathname, uri.query);
}
})
.listen(port, () => {
console.log(`Example app listening on port ${port}`);
// Distributor 와 통신 처리
const packet = makePacket('/distributes', 'POST', 0, {
port: process.env.GATE_PORT,
name: 'gate',
urls: [],
});
let isConnectedDistributor = false;
const clientDistributor = new TcpClient(
process.env.HOST,
process.env.DIS_PORT,
(options) => {
// 접속 이벤트
isConnectedDistributor = true;
clientDistributor.write(packet);
},
(options, data) => {
onDistribute(data);
}, // 데이터 수신 이벤트
(options) => {
isConnectedDistributor = false;
}, // 접속 종료 이벤트
(options) => {
isConnectedDistributor = false;
}, // 에러 이벤트
);
// 주기적인 Distributor 접속 상태 확인
setInterval(() => {
if (isConnectedDistributor !== true) {
clientDistributor.connect();
}
}, 3000);
// users 와 통신 처리
const packetLogin = makePacket('/users', 'POST', 0, {
port: process.env.USERS_PORT,
name: 'users',
urls: [],
});
let isConnectedLogin = false;
const clientLogin = new TcpClient(
process.env.HOST,
process.env.USERS_PORT,
(options) => {
// 접속 이벤트
isConnectedLogin = true;
clientLogin.write(packetLogin);
},
(options, data) => {
onLogin(data);
}, // 데이터 수신 이벤트
(options) => {
isConnectedLogin = false;
}, // 접속 종료 이벤트
(options) => {
isConnectedLogin = false;
}, // 에러 이벤트
);
// 주기적인 Distributor 접속 상태 확인
setInterval(() => {
if (isConnectedLogin !== true) {
clientLogin.connect();
}
}, 3000);
});
// API 호출 처리
export function onRequest(res, method, pathname, params) {
const key = method + pathname;
const client = mapUrls[key];
if (client == null) {
res.writeHead(404);
res.end();
} else {
const packet = makePacket(pathname, method, index, params);
mapResponse[`key_${index}`] = res;
index++;
if (mapRR[key] == null) {
mapRR[key] = 0;
}
mapRR[key]++;
client[mapRR[key] % client.length].write(packet);
}
}
export function onDistribute(data) {
for (let n in data.params) {
const node = data.params[n];
const key = node.host + ':' + node.port;
if (mapClients[key] == null && node.name !== 'gate') {
const client = new TcpClient(
node.host,
node.port,
onCreateClient,
onReadClient,
onEndClient,
onErrorClient,
);
mapClients[key] = {
client: client,
info: node,
};
for (let m in node.urls) {
const key = node.urls[m];
if (mapUrls[key] == null) {
mapUrls[key] = [];
}
mapUrls[key].push(client);
}
client.connect();
}
}
}
export function onLogin(data) {
for (let n in data.params) {
const node = data.params[n];
const key = node.host + ':' + node.port;
if (mapClients[key] == null && node.name !== 'users') {
const client = new TcpClient(
node.host,
node.port,
onCreateClient,
onReadClient,
onEndClient,
onErrorClient,
);
mapClients[key] = {
client: client,
info: node,
};
for (let m in node.urls) {
const key = node.urls[m];
if (mapUrls[key] == null) {
mapUrls[key] = [];
}
mapUrls[key].push(client);
}
client.connect();
}
}
}
// 마이크로서비스 접속 이벤트 처리
function onCreateClient(options) {
console.log('onCreateClient');
}
// 마이크로서비스 응답 처리
function onReadClient(options, packet) {
console.log('onReadClient', packet);
mapResponse[`key_${packet.key}`].writeHead(200, { 'Content-Type': 'application/json' });
mapResponse[`key_${packet.key}`].end(JSON.stringify(packet));
delete mapResponse[`key_${packet.key}`]; // http 응답 객체 삭제
}
// 마이크로서비스 접속 종료 처리
function onEndClient(options) {
const key = options.host + ':' + options.port;
console.log('onEndClient', mapClients[key]);
for (let n in mapClients[key].info.urls) {
const node = mapClients[key].info.urls[n];
delete mapUrls[node];
}
delete mapClients[key];
}
// 마이크로서비스 접속 에러 처리
function onErrorClient(options) {
console.log('onErrorClient');
}