๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๐Ÿ“‚ Web/Server

ํด๋ผ์ด์–ธํŠธ์˜ ์•ก์…˜์— ๋”ฐ๋ผ ๊ฐ๊ธฐ ๋‹ค๋ฅธ HTTP ์š”์ฒญ์„ ์„œ๋ฒ„๋กœ ๋ณด๋‚ด๊ณ , HTTP ์š”์ฒญ์— ๋‹ด์•„ ๋ณด๋‚ธ ๋‹จ์–ด๋ฅผ ์†Œ๋ฌธ์ž ๋˜๋Š” ๋Œ€๋ฌธ์ž๋กœ ์‘๋‹ต์„ ๋ฐ›์•„ ํ™”๋ฉด์— ๋ณด์—ฌ ์ฃผ๊ธฐ

by Dev. Ella 2023. 4. 4.

๐Ÿ“œ Bare minimum requirements

ํด๋ผ์ด์–ธํŠธ์˜ ์•ก์…˜(๋ฒ„ํŠผ ํด๋ฆญ)์— ๋”ฐ๋ผ ๊ฐ๊ธฐ ๋‹ค๋ฅธ HTTP ์š”์ฒญ์„ ์„œ๋ฒ„๋กœ ๋ณด๋‚ด๊ณ , HTTP ์š”์ฒญ์— ๋‹ด์•„ ๋ณด๋‚ธ ๋‹จ์–ด๋ฅผ ์†Œ๋ฌธ์ž ๋˜๋Š” ๋Œ€๋ฌธ์ž๋กœ ์‘๋‹ต์„ ๋ฐ›์•„ ํ™”๋ฉด์— ๋ณด์—ฌ ์ค๋‹ˆ๋‹ค.

 

 

๐Ÿ’ก ์กฐ๊ฑด

Endpoint(URL) Method ๊ธฐ๋Šฅ
/lower POST ๋ฌธ์ž์—ด์„ ์†Œ๋ฌธ์ž๋กœ ๋งŒ๋“ค์–ด ์‘๋‹ตํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค
/upper POST ๋ฌธ์ž์—ด์„ ๋Œ€๋ฌธ์ž๋กœ ๋งŒ๋“ค์–ด ์‘๋‹ตํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค

- POST์— ๋ฌธ์ž์—ด์„ ๋‹ด์•„ ์š”์ฒญ์„ ๋ณด๋‚ผ ๋•Œ๋Š” HTTP ๋ฉ”์‹œ์ง€์˜ body(payload)๋ฅผ ์ด์šฉํ•ฉ๋‹ˆ๋‹ค.
- ์„œ๋ฒ„๋Š” ์š”์ฒญ์— ๋”ฐ๋ฅธ ์ ์ ˆํ•œ ์‘๋‹ต์„ ํด๋ผ์ด์–ธํŠธ๋กœ ๋ณด๋‚ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
- CORS ๊ด€๋ จ ํ—ค๋”๋ฅผ OPTIONS ์‘๋‹ต์— ์ ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

- ํด๋ผ์ด์–ธํŠธ์˜ preflight request์— ๋Œ€ํ•œ ์‘๋‹ต์„ ๋Œ๋ ค์ค˜์•ผ ํ•ฉ๋‹ˆ๋‹ค.
- preflight request์— ๋Œ€ํ•œ ์‘๋‹ต ํ—ค๋”๋Š” ์ด๋ฏธ ์ž‘์„ฑ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

 

 

๐Ÿ“Ÿ ์„œ๋ฒ„ ์‹คํ–‰

ํ•ด๋‹น ๋””๋ ‰ํ† ๋ฆฌ๋กœ ์ง„์ž…ํ•œ ๋‹ค์Œ, ์•„๋ž˜ ์ปค๋งจ๋“œ๋ฅผ CLI์— ์ž…๋ ฅํ•˜๊ณ , ์„œ๋ฒ„๋ฅผ ์ข…๋ฃŒํ•˜๋ ค๋ฉด Ctrl+C๋ฅผ ๋ˆŒ๋Ÿฌ ํ”„๋กœ๊ทธ๋žจ์„ ๊ฐ•์ œ ์ข…๋ฃŒ

node server/basic-server.js

 

์„œ๋ฒ„ ์ฝ”๋“œ๋ฅผ ์ˆ˜์ •ํ•˜๊ณ  ์ €์žฅํ–ˆ๋‹ค๋ฉด ํ”„๋กœ๊ทธ๋žจ์„ ๋งค๋ฒˆ ๋‹ค์‹œ ์‹คํ–‰ํ•ด์•ผ ํ•˜์ง€๋งŒ, nodemon์„ ์ด์šฉํ•˜๋ฉด ์„œ๋ฒ„๋ฅผ ๋งค๋ฒˆ ์‹คํ–‰์‹œํ‚ฌ ํ•„์š”๊ฐ€ ์—†์ด npm start๋งŒ ์ž…๋ ฅํ•ด๋„ ๋จ

// 1. nodemon ์„ค์น˜
npm install nodemon

// 2. package.json์˜ "scripts"์— ์•„๋ž˜ ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€
"start": "nodemon server/basic-server.js"

// 3. ์ดํ›„ ์„œ๋ฒ„ ์‹คํ–‰ ์‹œ npm start๋งŒ ์ž…๋ ฅํ•˜๋ฉด ๋œ๋‹ค.

 

 

๐Ÿ“ก ํด๋ผ์ด์–ธํŠธ ์‹คํ–‰

Client/index.html ์„ ์›น ๋ธŒ๋ผ์šฐ์ €์—์„œ ์‹คํ–‰ํ•˜๊ฑฐ๋‚˜, ํŠน์ • ํฌํŠธ๋กœ ์‹คํ–‰ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด serve ์ด์šฉ

npx serve -l ํฌํŠธ๋ฒˆํ˜ธ client/

 

 

โœ๐Ÿป ๋‚ด ์ฝ”๋“œ 1 : ์š”์ฒญ body์—์„œ ๋ฌธ์ž์—ด ์„ ์–ธ

const http = require('http');
const PORT = 4999;
const ip = 'localhost';

const server = http.createServer((request, response) => {
  // CORS ๊ด€๋ จ ํ—ค๋”๋ฅผ OPTIONS ์‘๋‹ต์— ์ ์šฉ
  // Method๊ฐ€ OPTIONS์ธ์ง€ ๋ถ„๊ธฐ
  if (request.method === 'OPTIONS') {
    response.writeHead(200, defaultCorsHeader);
    response.end();
  }
  // Method๊ฐ€ POST๋ผ๋ฉด url ํ™•์ธ ํ›„ ์•Œ๋งž์€ ์š”์ฒญ์„ ๋ณด๋‚ด์ฃผ๊ธฐ
  if (request.method === 'POST') {
    // Method๊ฐ€ POST๊ณ  url์ด /lower๋ผ๋ฉด
    if(request.url === '/lower') {
      // ๋นˆ ๋ฌธ์ž์—ด ์„ ์–ธ
      let data = '';
      request.on('data', chunk => {
        data = data + chunk;
      });
      request.on('end', () => {
        data = data.toLowerCase();
        // ์†Œ๋ฌธ์ž๋กœ ๋œ ์‘๋‹ต์„ ๋Œ๋ ค์ฃผ๊ธฐ
        response.writeHead(201, defaultCorsHeader);
        response.end(data);
      });
    // Method๊ฐ€ POST๊ณ  url์ด /upper๋ผ๋ฉด
    } else if (request.url === '/upper') {
      let data = '';
      request.on('data', chunk => {
        data = data + chunk;
      });
      request.on('end', () => {
        data = data.toUpperCase();
        // ๋Œ€๋ฌธ์ž๋กœ ๋œ ์‘๋‹ต์„ ๋Œ๋ ค์ฃผ๊ธฐ
        response.writeHead(201, defaultCorsHeader);
        response.end(data);
      });
    // ์œ„ ๋‘ ๊ฐ€์ง€ ๊ฒฝ์šฐ ๋ชจ๋‘ ์•„๋‹ˆ๋ผ๋ฉด
    } 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
};

 

 

โœ๐Ÿป ๋‚ด ์ฝ”๋“œ 2 : ์š”์ฒญ body์—์„œ ๋ฐฐ์—ด ์„ ์–ธ

const http = require('http');
const PORT = 4999;
const ip = 'localhost';

const server = http.createServer((request, response) => {
  // CORS ๊ด€๋ จ ํ—ค๋”๋ฅผ OPTIONS ์‘๋‹ต์— ์ ์šฉ
  // Method๊ฐ€ OPTIONS์ธ์ง€ ๋ถ„๊ธฐ
  if (request.method === 'OPTIONS') {
    // ํด๋ผ์ด์–ธํŠธ์˜ preflight request์— ๋Œ€ํ•œ ์‘๋‹ต
    response.writeHead(200, defaultCorsHeader);
    response.end();
  }
  // Method๊ฐ€ POST๋ผ๋ฉด url ํ™•์ธ ํ›„ ์•Œ๋งž์€ ์š”์ฒญ์„ ๋ณด๋‚ด์ฃผ๊ธฐ
  if (request.method === 'POST') {
    // PUT request body(payload) ------------------
    // ๋นˆ ๋ฐฐ์—ด๋กœ ์„ ์–ธ
    let body = [];
    request
    // 'data'์— ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ ๋“ฑ๋กํ•ด ๋ฐ์ดํ„ฐ ๋ฐ›๊ธฐ
      .on('data', (chunk) => {
        // body ๋ฐฐ์—ด์— chunk๋ฅผ ๋‹ด๊ธฐ
        body.push(chunk);
      })
    // 'end'์— ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ ๋“ฑ๋กํ•ด ๋ฐ์ดํ„ฐ ๋ฐ›๊ธฐ
      .on('end', () => {
        // 'data' ์ด๋ฒคํŠธ์—์„œ ๋ฐœ์ƒ์‹œํ‚จ ์ฒญํฌ Buffer(๋ฌธ์ž์—ด ๋ฐ์ดํ„ฐ)๋ฅผ ๋ฐฐ์—ด์— ์ˆ˜์ง‘ ํ›„
        // end ์ด๋ฒคํŠธ์—์„œ ์ด์–ด ๋ถ™์ด๊ณ  ๋ฌธ์ž์—ด๋กœ ๋งŒ๋“ค๊ธฐ
        body = Buffer.concat(body).toString();
        response.writeHead(201, defaultCorsHeader);
        
        // Method๊ฐ€ POST๊ณ  url์ด /lower๋ผ๋ฉด
        if (request.url === '/lower') {
          // ์†Œ๋ฌธ์ž๋กœ ๋œ ์‘๋‹ต์„ ๋Œ๋ ค์ฃผ๊ธฐ
          response.end(body.toLowerCase());
        
        // Method๊ฐ€ POST๊ณ  url์ด /upper๋ผ๋ฉด
        } 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,
};

 

 

๐Ÿ“ก ๊ฒฐ๊ณผ ํ™”๋ฉด

๋Œ€๋ฌธ์ž๋ฅผ ์ž…๋ ฅํ•˜๋ฉด ์†Œ๋ฌธ์ž๋กœ, ์†Œ๋ฌธ์ž๋ฅผ ์ž…๋ ฅํ•˜๋ฉด ๋Œ€๋ฌธ์ž๋กœ ๋‚˜์™€์•ผ ํ•˜๋ฉฐ, ๊ฐœ๋ฐœ์ž ๋„๊ตฌ์—์„œ๋„ ์—๋Ÿฌ ์—†์ด ์ž˜ ๋„์›Œ์ง€๋ฉด ์„ฑ๊ณต์ด๋‹ค.

 

๐Ÿ‘ฉ๐Ÿป‍๐Ÿ’ป ๋ฐฐ์šด ์ 

์ฒ˜์Œ์—๋Š” HTTP ํŠธ๋žœ์žญ์…˜ ํ•ด๋ถ€์— ๋‚˜์™€์žˆ๋Š” ๋Œ€๋กœ ๋ฐฐ์—ด์„ ์„ ์–ธํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ–ˆ๋Š”๋ฐ, ์ด์œ ๋Š” ๋ชจ๋ฅด๊ฒ ์ง€๋งŒ ๋ฉ”์†Œ๋“œ๋„ ์•ˆ ๋œจ๊ณ  ์—๋Ÿฌ๊ฐ€ ๋– ์„œ ๋ฌธ์ž์—ด์„ ์„ ์–ธํ•˜๋Š” ๋ฐฉ๋ฒ•์œผ๋กœ ๋ณ€๊ฒฝํ•ด ์‹œ๋„ํ–ˆ๋”๋‹ˆ ์„ฑ๊ณตํ–ˆ๋‹ค.

 

๋‹ค ๋๋‚ด๋†“๊ณ  ์›์ธ์„ ์•Œ์•˜๋Š”๋ฐ, nodemon์„ ์„ค์น˜ํ•˜๋ฉด ์ฒ˜์Œ๋ถ€ํ„ฐ ์„œ๋ฒ„ ์‹คํ–‰์„ ๋”ฐ๋กœ ์•ˆํ•ด๋„ ๋˜๋Š” ์ค„ ์•Œ์•˜๋˜ ๊ฒƒ์ด๋‹ค. nodemon์„ ์„ค์น˜ํ•œ ์ด์œ ๋Š” ์ฝ”๋“œ๋ฅผ ์ˆ˜์ •ํ•  ๋•Œ๋งˆ๋‹ค node server/basic-server.js๋กœ ์„œ๋ฒ„๋ฅผ ์‹คํ–‰ํ•˜์ง€ ์•Š์•„๋„ ๋˜๊ณ , ์ฒ˜์Œ์— npm start๋งŒ ์ž…๋ ฅํ•ด๋„ ์ฝ”๋“œ ์ˆ˜์ •๊ณผ ๋™์‹œ์— ์„œ๋ฒ„๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ด์—ˆ๋‹ค.

 

์ฝ”๋“œ๋Š” ๋‹ค ์จ๋†“๊ณ  ์„œ๋ฒ„ ์‹คํ–‰ ๋ฐฉ๋ฒ•์— ์ต์ˆ™ํ•˜์ง€ ์•Š์•„ ๋‚ ๋ ค๋ฒ„๋ฆฐ๊ฑด ๋งค์šฐ ์•ˆํƒ€๊นŒ์› ๋˜ ์ผ... ํ•˜์ง€๋งŒ ๊ฒฐ๊ณผ์ ์œผ๋กœ๋Š” ์ฝ”๋“œ ํ•œ ์ค„ ํ•œ ์ค„ ๋” ์ž์„ธํžˆ ๋œฏ์–ด๋ณด๊ณ , HTTP ํŠธ๋žœ์žญ์…˜ ํ•ด๋ถ€ ๊ฐ€์ด๋“œ๋„ ๋” ์ž์„ธํžˆ ์ฝ์–ด๋ณด๊ณ , ๋‘ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•˜๋ฉด์„œ ์ดํ•ด๊ฐ€ ์ž˜ ๋˜์—ˆ๋‹ค. ์˜ค๋Š˜์˜ ์‹œํ–‰์ฐฉ์˜ค๊ฐ€ ๊ฒฐ์ฝ” ํ—›๋˜์ง€ ์•Š์•˜๋‹ค. 

 

 

๐Ÿ“Ž ์ฐธ๊ณ  ์ž๋ฃŒ

- ์ฝ”๋“œ์Šคํ…Œ์ด์ธ  ์œ ์–ดํด๋ž˜์Šค ์ž๋ฃŒ

- HTTP ํŠธ๋žœ์žญ์…˜ ํ•ด๋ถ€

๋Œ“๊ธ€