본문 바로가기

내일 배움 캠프/그땐 (응답하라 추억시대)

Node.js TCP서버에서 query와 params를 이용하여 CRUD 하기

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');
}