새소식

프론트엔드 공부/Web Server

Mini Node Server

  • -

들어가기 앞서 참고(트랜젝션 해부)

 

HTTP 트랜잭션 해부 | Node.js

Node.js® is a JavaScript runtime built on Chrome's V8 JavaScript engine.

nodejs.org

Node.js가 제공하고 있는 HTTP 트랜잭션 해부(Anatomy of an HTTP Transaction) 공식 가이드 문서를 통해 Mini-Node Server를 완성하는 데 도움을 받을 수 있습니다!


과제 실행에 앞서 깃허브 포크 받고 클론하는 과정은 생략.

서버 실행

node server/basic-server.js

위와 같이 노드 서버를 실행했을때 코드를 수정하고 저장했다면 프로그램을 매번 서버를 Ctrl+C를 눌러 종료했다가 npm start로  다시 시작해야 한다.

어지간히 불편한 일이다. 이러한 번거로움을 없애고자 서버를 매번 실행시키지 않아도 되는 개발도구가 있다. 

nodemon을 이용하는 방법이다.

먼저 CLI(command-line interface)에 npm intall nodemon을 입력하여 설치한다.

npm install nodemon

그리고 클론받은 파일의 폴더안에 pakage.json의 "scripts"에 아래 코드를 추가한다.

"start": "nodemon server/basic-server.js"

위 방식으로 nodemon을 설치하고 스크립트에 추가하였다면 CLI에서 바로 입력하면 저장 후 매번 새로 start하지 않아도 적용이 된다.

node server/basic-server.js

node server/basic-server.js 입력시 로컬호스트 연결

만약 위 방법처럼 nodemon 을 따로 설치하지 않고 실행하고자 한다면 터미널에서 바로 실행하면 된다.

npx nodemon server/basic-server.js //npx nodemon으로 server/basic-server.js 파일을 실행합니다.

 


클라이언트 실행

클론받은 폴더에서 client/index.html를 웹 브라우저에서 실행하면 기본적으로 작성된 버튼과 입력란을 볼 수 있다.

특정 포트로 클라이언트를 실행하고 싶다면, serve를 이용할 수 있습니다.

npx serve -l 포트번호 client/

Bare minimum requirements

이번 과제에서 구현하는 웹 서버의 기능은 매우 단순합니다. 클라이언트의 액션(버튼 클릭)에 따라 각기 다른 HTTP 요청을 서버로 보내고, HTTP 요청에 담아 보낸 단어를 소문자 또는 대문자로 응답을 받아 화면에 보여 줍니다.

과제의 조건

  • POST에 문자열을 담아 요청을 보낼 때는 HTTP 메시지의 body(payload)를 이용합니다.
  • 서버는 요청에 따른 적절한 응답을 클라이언트로 보내야 합니다.
  • CORS 관련 헤더를 OPTIONS 응답에 적용해야 합니다.
    • 클라이언트의 preflight request에 대한 응답을 돌려줘야 합니다.
    • preflight request에 대한 응답 헤더는 이미 작성되어 있습니다.

 

클론받은 파일의 basick-server.js 를 열어보면 이러한 상태다.

const http = require('http');

const PORT = 4999;

const ip = 'localhost';

const server = http.createServer((request, response) => {
  console.log(
    `http request method is ${request.method}, url is ${request.url}`
  );
  response.writeHead(200, defaultCorsHeader);
  response.end('hello mini-server sprints');
});
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
};

특정 도메인에 대한 cors 허용된 부분

const defaultCorsHeader = {
  // 이 부분에 특정 origin을 작성해준다.
  "Access-Control-Allow-Origin": "http://localhost:5000",
  "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS",
  "Access-Control-Allow-Headers": "Content-Type, Accept",
  "Access-Control-Max-Age": 10,
};

서버 부분에 요청에 대한 기능 구현하기 위해 작성되어야 하는 방식은 이러하다.

if(메소드가 post이고, url이 /upper이면){
	대문자로 응답 
}else if(메소드가 post이고, url이 /lower이면){
	소문자로 응답 
}else{
	나머지는 에러로 처리 -> bad request
}

위 형식을 지켜서 작성해보면 아래와 같다.

해결 코드

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

// "preflighted" request는 "simple requests” 와는 달리, 
// 먼저 OPTIONS 메서드를 통해 다른 도메인의 리소스로 HTTP 요청을 보내 
// 실제 요청이 전송하기에 안전한지 확인한다.
const server = http.createServer((request, response) => {
// 메소드가 options, CORS 설정(defaultCorsHeader)을 돌려줘야 한다.
// CORS (body가 필요없기 때문에 headers만 넘어온다)
    if(request.method === "OPTIONS"){
    response.writeHead(200, defaultCorsHeader); 
    //writeHead메소드를 이용해 헤더 데이터를 전송한다.(https://nodejs.org/api/http.html#responsewriteheadstatuscode-statusmessage-headers) 
    response.end(); //end메소드는 모든 응답 헤더와 본문이 전송되었음을 서버에 알린다
    }

    //   메소드가 POST고 URL이 /upper 이면 대문자 응답을 돌려줘야 한다.
    //   "on"이라는 메소드는 지정된 이벤트(유저의 버튼 클릭이나 네트워크에 리소스를 요청하는 것 등) 
    //   처리를 통합하는 것으로, 첫번째 인수에 이벤트 이름을, 두번째 인수에 통합 처리(함수)를 각각 지정한다.
    //   request.on('data', ) 부분은 request 요청에서 데이터 도착시라고 생각  
    if(request.method === 'POST' && request.url === "/upper"){
        let body = [];
        request.on('data', (chunk) => {
            body.push(chunk);
        }).on('end', () => { //.on('end',) request 요청에서 데이터가 다 전달되었으면 
            body = Buffer.concat(body).toString().toUpperCase(); //바로 문자열로 바꾼부분에 대문자로 바꿔주었다.
            response.writeHead(200, defaultCorsHeader);
            response.end(body);
        })
    }
    // 메소드가 POST, URL이 /lower 이면 소문자로 응답을 돌려줌
    else if(request.method === "POST" && request.url === "/lower"){
        let body = [];
        request.on('data', (chunk) => {
            body.push(chunk);
        }).on('end', () => {
            body = Buffer.concat(body).toString().toLowerCase();
            response.writeHead(200, defaultCorsHeader);
            response.end(body);
        })
    }
    // 그외는 에러처리, bad request
    else{
    response.statusCode = 404;
    response.end();
    }

    // 이 부분은 위에서 작성된것이기에 이곳에서 반복되면 오류가 난다. 위에서 작성되니 삭제해야함
    // console.log(
    // `http request method is ${request.method}, url is ${request.url}`
    // );
    // response.writeHead(200, defaultCorsHeader);
    // response.end('hello mini-server sprints');
});


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

위 작성된 코드를 조금 더 보기 좋게 정리하면 아래와 같이 정리된다. 단지 중간에 반복되는 if문을 묶어준것.

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

const server = http.createServer((req, res) => {
  if (req.method === 'OPTIONS') {
    res.writeHead(200, defaultCorsHeader);
    res.end();
  }
  if (req.method === 'POST') {
    let body = [];
    req.on('data', chunk => body.push(chunk)).on('end', () => {
      body = Buffer.concat(body).toString();
      if (req.url === '/upper') body = body.toUpperCase();
      if (req.url === '/lower') body = body.toLowerCase();
      res.writeHead(200, defaultCorsHeader);
      res.end(body);
    });
  } else {
    res.statusCode = 404;
    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
};

'프론트엔드 공부 > Web Server' 카테고리의 다른 글

세션(블로깅중)  (0) 2023.03.07
쿠키란 무엇일까? 개념, 필요성, 속성, 문제점  (0) 2023.03.07
[Web Server] 기초 종합퀴즈  (0) 2023.02.08
StatesAirline Server  (0) 2023.02.08
SOP, CORS  (0) 2023.02.06
Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.