본문 바로가기
Node.js

[Backend] http 모듈로 서버 만들기

by Hangii 2023. 1. 30.

HTTP 서버 만들기

웹 브라우저에 www.naver.com 을 입력하면, 웹 브라우저가 client가 되는 것이고, 서버는 네이버의 서버(서버는 어떤 컴퓨터이다)가 된다. 클라이언트가 서버에 '메인 화면을 띄워달라'는 요청을 하면, 서버에서 이를 받아 화면을 띄우는 응답을 한다. 요청과 응답은 http라는 프로토콜을 사용해서 이루어진다.

 

노드에서는 http라는 모듈을 사용해서 코드를 작성하면 노드 프로그램을 돌릴 수 있다. createServer를 사용해 요청 이벤트에 대기할 수 있다. req 객체에는 요청에 관한 정보가, res 객체에는 응답에 관한 정보가 담겨 있다. 

createServer.js

const http = require('http');

const server = http.createServer((req,res) => {
	//여기에 요청에 대해서 어떻게 응답할지 적는다.
    //악성 유저로 판단되면 거절, 아니면 승인
    res.write('<h1>Hello Node!</h1>');
    res.write('<p>Hello server</p>'); 
    res.end('<p>Hello ZeroCho</p>'); 
})
	.listen(8080, () => {
    	console.log('8080번 포트에서 서버 대기 중입니다.');  //8080번 포트가 켜지면 터미널에 출력.
    })  //노드도 프로그램이기 때문에 이 프로그램을 프로세스에 올려줘야 한다.
    	//listen은 실행하면 terminal 하나를 잡아먹는다.
        
//에러 처리
server.on('error', (error) => {
	console.error(error);
});

포트는 서버 내에서 프로세스를 구분하는 번호이다. 기본적으로http 서버는 80번 포트를 사용하고(생략 가능), https는 443번 포트를 사용한다(생략 가능). 여러 개의 포트를 사용해 다른 서버에 동시에 연결하는 것도 가능하다.

서버를 켜둔 채로 코드를 수정한 경우, 서버에 변경된 코드가 바로 적용되지 않으므로 서버를 한 번 껐다가 켜줘야 한다. 

 

fs로 html 읽어 제공하기

safari와 같은 몇개의 브라우저들은 server의 응답이 html코드인지 단순 문자열인지 구분하지 못한다. 이런 경우, 프로그래머가 직접 html코드임을 명시해야 한다. 

const http = require('http');

const server = http.createServer((req,res) => {
	res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
})

동시에 두 개의 서버 실행하기

const http = require('http');

const server = http.createServer((req,res) => {
	//여기에 요청에 대해서 어떻게 응답할지 적는다.
    //악성 유저로 판단되면 거절, 아니면 승인
    res.write('<h1>Hello Node!</h1>');
    res.write('<p>Hello server</p>'); 
    res.end('<p>Hello ZeroCho</p>'); 
})
	.listen(8080);
server.on('listening' , () => {
    console.log('8080번 포트에서 서버 대기 중입니다.');  //8080번 포트가 켜지면 터미널에 출력.
});
server.on('error', (error) => {
	console.error(error);
});

const server1 = http.createServer((req,res) => {
	//여기에 요청에 대해서 어떻게 응답할지 적는다.
    //악성 유저로 판단되면 거절, 아니면 승인
    res.write('<h1>Hello Node!</h1>');
    res.write('<p>Hello server</p>'); 
    res.end('<p>Hello ZeroCho</p>'); 
})
	.listen(8081);

서버에서 응답으로 출력할 html 파일을 미리 만들어 두고 fs를 사용해 이를 읽어올 수 있다.

server2.js

const http = require('http');
const fs = require('fs').promises;

const server = http.createServer(async (req, res) => {
	try{  //try-catch문을 사용해 에러 처리를 하는 것이 중요하다.
	res.writeHead(200, {'Content-Type': 'text/html; charset=utf-8'});
    const data = await fs.readFile('./server2.html');
    res.end(data);
    } catch(error) {
		console.error(error);
        res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' });  //plain사용해 일반 문자열임을 알려준다.
        res.end(err.message);
    }
})

server2.html

<!DOCTYPE html>
<html>
	<head>
    	<meta charset="utf-8">
        <title>Node.js 웹서버</title>
    </head>
    <body>
    	<h1>Node.js 웹 서버</h1>
        <p>만들 준비 되셨나요?</p>
    </body>
</html>

 

REST API 서버 만들기

서버에 요청을 보낼 때는 주소를 통해 요청의 내용을 표현한다.

  • /index.html이면 index.html을 보내달라는 뜻
  • 항상 html을 요구할 필요는 없다. (이미지, js, 아이디가 'hhk'인 사용자 정보 등을 요구해도 됨)
  • client의 요청을 받아들이는 주도권은 서버에게 있다. 보통 서버에서 정해준 주소 규칙을 따라 client에서 요청을 보낸다. 주소 규칙 중 가장 보편적인 것이 REST API이다.

REST API(Representational State Transfer)

  • 서버의 자원을 정의하고 자원에 대한 주소를 지정하는 방법이다.
  • /user이면 사용자 정보에 관한
  • /post이면 게시글에 관련된 자원을 요청하는 것

HTTP 요청 메서드

  • GET: 서버 자원을 가져오려고 할 때 사용
  • POST: 서버에 자원을 새로 등록하고자 할 때 사용(또는 뭘 써야할 지 애매할 때)
  • PUT: 서버의 자원을 요청에 들어있는 자원으로 치환하고자 할 때 사용(보통 전체 수정할 때)
  • PATCH: 서버 자원의 일부만 수정하고자 할 때 사용(보통 부분적으로 수정할 때)
  • DELETE: 서버의 자원을 삭제하고자 할 때 사용

client가 누구든 이 HTTP 프로토콜을 사용하기만 한다면 소통이 가능하다. iOS, 안드로이드, 웹이 모두 같은 주소로 요청을 보낼 수 있다. REST API를 사용한 주소 체계를 이용하는 서버를 RESTful 서버라고 한다. 다음 표는 RESTful 서버의 주소 구조 예시이다.

HTTP 메서드 주소 역할
GET / restFront.html 파일 제공
GET /about about.html 파일 제공
GET /users 사용자 목록 제공
GET 기타 기타 정의 파일 제공
POST /users 사용자 등록
PUT /users/사용자.txt 해당 txt의 사용자 수정
DELETE /users/사용자.txt 해당 txt의 사용자 제거

 

쿠키 이해하기

쿠키의 필요성

  • client에서 요청을 보냈을 때, 서버에서는 이 요청을 누가 보냈는지 알 수 없음(IP주소와 브라우저 정보 정도만 앎)
  • 이 문제를 해결하기 위해 쿠키와 세션이 필요

쿠키: 키=값의 쌍

  • name=hhk 와 같이 매 요청마다 누가 요청을 보내는지에 대한 정보를 동봉해서 보냄
  • 서버는 쿠키를 읽어 누구인지 파악한다.
  • 첫 응답 시, 서버 측에서 클라이언트에게 쿠키와 함께 응답을 보낸다. 이후 클라이언트는 쿠키와 함께 요청을 보내고, 서버는 누가 요청을 보냈는지 알 수 있게 된다.

 

쿠키 서버 만들기

쿠키 넣는 것을 직접 구현하기

  • writeHead: 요청 헤더에 입력하는 메서드
  • Set-Cookie: 브라우저에게 쿠키를 설정하라고 명령

cookie.js

const http = require('http');

http.createServer((req, res) => {
	console.log(req.url, req.headers.cookie);
    res.writeHead(200, { 'Set-Cookie': 'mycookie=test' });
    res.end('Hello Cookie');
})
	.listen(8083, () => {
    	console.log('8083번 포트에서 서버 대기 중입니다!');
    });

 

[콘솔창]

$ node cookie

8083번 포트에서 서버 대기 중입니다.

 

http 요청과 응답은 헤더와 본문은 가짐

  • 헤더는 요청 또는 응답에 대한 정보를 가짐
  • 본문은 주고받는 실제 데이터
  • 쿠키는 부가적인 정보이므로 헤더에 저장됨

쿠키 옵션

Set-Cookie 시 다양한 옵션이 있음

  • 쿠키명=쿠키값: 기본적인 쿠키의 값이다. mycookie=test 또는 name=hhk 와 같이 설정한다.
  • Expires=날짜: 만료 기한이다. 이 기한이 지나면 쿠키가 제거된다. 기본값은 클라이언트가 종료될 때까지이ㄴ다.
  • Max-age=초: Expires와 비슷하지만 날짜 대신 초를 입력할 수 있다. 해당 초가 지나면 쿠키가 제거된다. Expires보다 우선이다.
  • Domain=도메인명: 쿠키가 전송될 도메인을 특정할 수 있다. 기본값은 현재 도메인이다.
  • Path=URL: 쿠키가 전송될 URL을 특정할 수 있다. 기본값은 '/'이고, 이 경우 모든 URL에서 쿠키를 전송할 수 있다.
  • Secure: HTTPS일 경우에만 쿠키가 전송된다.
  • HttpOnly: 설정 시 자바스크립트에서 쿠키에 접근할 수 없다. 쿠키 조작을 방지하기 위해 설정하는 것이 좋다.

 

세션 사용하기 

쿠키의 정보는 노출되고 수정되는 위험이 있다. 따라서 중요한 정보는 브라우저에 직접 보내지 않고 서버에 보관하며, 중요 정보에 접근할 수 있는 key 정보만 서버에 저장해두는 방법을 세션이라고 부른다. 

  • 서버에 세션 객체(session) 생성 후, uniqueInt(키)를 만들어 속성명으로 사용 가능
  • 속성 값에 정보를 저장하고 uniqueInt를 클라이언트에 보냄
  • uniqueInt는 안겹치게 만들어야 한다. 
  • 브라우저에는 uniquInt값만을 보낸다. 

실 서버에서는 세션을 직접 구현하지 말자

  • 6장의 express-session사용하기

 

http와 http2

https: 웹 서버에 SSL암호화를 추가하는 모듈

http를 사용하는 경우, 요청 헤더에 너무 많은 정보가 노출되어 탈취의 위험이 있다. 노드에서는 http를 https로 바꿀 수 있다. 이를 위해 인증서를 발급받아야 한다.

 

createServer가 인자를 두 개 받는다.

  • 첫 번째 인자는 인증서와 관련된 옵션 객체이다.
  • pem, crt, key 등 인증서를 구입할 때 얻을 수 있는 파일을 넣는다.
  • 두 번째 인자는 서버 로직이다.

http2: SSL 암호화와 더불어 최신 HTTP 프로토콜인 http/2를 사용하는 모듈

  • 요청 및 응답 방식이 기존 http/1.1보다 개선됨
  • 웹의 속도도 개선됨

 

cluster

기본적으로 싱글 스레드인 노드가 CPU 코어를 모두 사용할 수 있게 해주는 모듈이다.

  • 포트를 공유하는 노드 프로세스를 여러 개 둘 수 있음
  • 요청이 많이 들어왔을 때 병렬로 실행된 서버의 개수만큼 요청이 분산됨
  • 서버에 무리가 덜 감
  • 코어가 8개인 서버가 있을 때, 보통을 코어를 하나만 이용함
  • cluster로 코어 하나당 노드 프로세스 하나를 배정 가능함
  • 성능이 8배가 되는 것은 아니지만 개선됨
  • 단점: 컴퓨터 자원(메모리, 세션 등) 공유 못 함
  • Redis 등 별도 서버로 해결

 

'Node.js' 카테고리의 다른 글

[Backend] 패키지 매니저  (0) 2023.01.30
[Backend] 노드 기능  (0) 2023.01.26
[Backend] 프로미스  (1) 2023.01.26
비구조화 할당  (0) 2023.01.26
화살표 함수  (0) 2023.01.25

댓글