Node.js로 웹 개발하기 - 01. 웹 서버 만들기

2024. 12. 26. 14:58Programming Language/Node.js

01. 웹서버란?

웹서버란 클라이언트(보통 웹 브라우저)가 요청한 웹 페이지, 이미지, 동영상 등과 같은 콘텐츠를 제공하는 서버 소프트웨어 또는 하드웨어를 말한다.

웹 서버는 주로 인터넷이나 내부 네트워크를 통해 HTTP(HyperText Transfer Protocol)를 사용하여 클라이언트와 통신한다

 

웹서버의 종류

웹서버는 크게 두 가지 방식으로 나뉜다.

  • 정적 웹 서버

클라이언트 요청에 대해 준비된 정적인 컨텐츠(HTML 파일, 이미지 파일, CSS 파일등..)를 전달하는 서버를 말한다.

정적 웹 서버의 종류로는 대표적으로 Apache, Nginx가 있다

  • 동적 웹 서버

클라이언트의 요청에 따라 실시간으로 데이터를 생성하고 처리한 뒤에 그 결과를 반환한다.

동적 웹 서버의 종류로는 Node.js, PHP, Python(Django/Flask), Ruby on Rails 등이 있다.

 

웹 서버의 작동 원리

1. 사용자가 브라우저의 URL창에 URL을 입력하면 브라우저는 이를 DNS(Domain Name Server)에서 이름을 뒤져서 해당 서버의 IP주소를 찾은 후에 그 IP주소로 HTTP 요청을 전송한다

 

2. 웹 서버는 이 클라이언트의 요청을 해석해서 필요한 리소스들을 찾기 시작하는데 정적 리소스를 요청할 때파일을 그대로 반환해주고, 동적 리소스를 요청할 때에는 서버에서 애플리케이션 로직을 실행한 후에 결과를 생성해서 반환해준다.

 

3. 그리고 이 반환 값을 HTTP 응답 상태코드(ex. 200 OK, 404 Not Found...)와 함께 HTML, JSON등의 요청한 데이터의 형태로 클라이언트에게 반환한다.

 

02. HTTP Requests

HTTP Requests 는 클라이언트(보통 웹 브라우저나 애플리케이션)가 서버에 특정 작업을 요청하기 위한 메시지를 통칭하는 말이다.

 

HTTP Method

HTTP 요청의 동작 방식을 정의하는 메서드로 주요 메서드는 GET, POST, PUT, DELETE 등이 있다.

 

  • GET - 서버에서 데이터를 가져오기 위한 메서드

클라이언트(웹 브라우저 또는 애플리케이션)가 서버에서 데이터를 요청할 때 사용된다.

주로 웹 페이지, 이미지, JSON 데이터 등을 가져오기 위해 사용되며, 가장 일반적이고 기본적인 HTTP 메서드이다.

 

GET 메서드는 서버로부터 리소스(데이터)를 가져오기 위한 용도이기에 데이터를 변경하거나 삭제하지 않는다.

GET 요청은 데이터를 쿼리 스트링(query string) 형식으로 URL에 포함해 전달한다.

GET 메서드는 요청에 본문이 존재하지 않고 모든 데이터는 URL을 통해 전달된다.

 

  • POST

클라이언트(브라우저 또는 애플리케이션)가 서버에 데이터를 전송하고, 주로 리소스를 생성하거나 서버 상태를 변경할 때 사용된다.

 

POST는 데이터를 요청 본문(Body)에 담아 서버로 전송하고 전송된 데이터는 주로 데이터베이스에 저장하거나, 서버에서 처리 후 응답으로 반환된다

POST 요청은 서버에 리소스를 생성하거나 기존 데이터를 수정하는 작업에 사용된다(ex. 회원가입, 게시글 작성, 데이터 입력 )

POST는 데이터를 요청 본문에 포함하므로, GET 메서드와 달리 URL에 데이터가 노출되지 않는다.

또한 URL 길이 제한에 대한 문제점도 발생하지 않는다.

  • PUT - 기존 리소스 전체 업데이트 또는 생성한다
  • PATCH - 기존 리소스 일부 업데이트한다
  • DELETE - 리소스 삭제한다.

03. Stateless Protocol

Stateless Protocol(무상태 프로토콜)는 HTTP의 대표적인 특성이다.

이는 클라이언트와 서버 간의 통신에서, 서버가 클라이언트의 이전 요청 상태를 기억하지 않는 통신 방식을 의미한다.

각 HTTP 요청은 완전히 독립적이며, 이전 요청과는 아무런 연관이 없다.

 

HTTP에서 상태 유지(State Management)를 위한 보완 방법으로 쿠키(Cookie), 세션(Session), JWT(JSON Web Token), URL 파라미터(Query String) 등을 이용한다.

 

04. HTTP Request, Response의 구조

HTTP 통신은 클라이언트(보통 웹 브라우저)와 서버 간의 요청(Request)과 응답(Response)으로 이루어진다.

 

Request의 구조

클라이언트가 서버에 특정 작업을 요청할 때 사용하는 메시지로 Request의 구조는 요청 라인, 헤더, 본문 3개의 구성요소로 이루어져 있다.

 

요청 라인(Request Line)

요청 라인은 HTTP Request의 첫 번째 줄로, 서버에 어떤 요청을 할 것인지를 정의하는데 이 요청라인은 HTTP 메서드 (HTTP Method), URI (Uniform Resource Identifier), HTTP 버전 (HTTP Version) 세 부분으로 나뉜다.

 

  • HTTP 메서드 (HTTP Method)

요청하려는 작업의 종류를 정의하는 부분으로 클라이언트가 서버에서 요청에 의해 수행하려는 동작을 나타낸다.

이 메서드가 위에서 봤던 GET, POST, PUT, PATCH, DELETE이다.

 

  • URI (Uniform Resource Identifier)

URI는 요청하려는 자원의 경로 또는 위치를 나타낸다. 

이는 클라이언트가 요청하는 리소스의 위치가 되고 서버는 이 경로를 통해서 요청을 처리하고 응답하게 된다.

이 URI는 절대 URI(서버의 루트부터 시작하는 전체 경로, ex) /products, /images/logo.png)와 상대 URI(현재 경로에 대한 상대적인 위치, ex) /profile, user/123 )

 

  • HTTP 버전 (HTTP Version)

HTTP 프로토콜의 버전을 명시한다.

이는 서버와 클라이언트가 사용하는 프로토콜 버전을 알려주는데 보통 HTTP/1.1 또는 HTTP/2가 사용된다.

 

이렇게 구성된 요청라인의 전체는 

GET /products HTTP/1.1
POST /login HTTP/1.1

 

헤더 (Headers)

헤더는 요청에 대한 부가적인 정보를 포함하는 영역이다.

헤더는 여러 줄로 구성되며, 각 줄은 "Header-Name: Header-Value" 형태로 작성된다.

요청 헤더는 클라이언트가 서버에 보내는 메타데이터로, 요청에 대한 세부 사항을 설명해준다.

  • Host

요청을 보낸 서버의 도메인 이름을 명시한다. 

HTTP/1.1에서는 이 헤더가 필수이다.

 

ex) Host: www.example.com   

 

  • User-Agent

클라이언트의 웹 브라우저 정보 또는 애플리케이션 정보를 전달합니다.

 

ex) User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36

 

  • Accept

클라이언트가 받을 수 있는 콘텐츠 유형을 명시합니다.

 

ex) Accept: text/html (=> 나 html로 받을수 있어!) , Accept: application/json(=> 나 json으로 받을 수 있어!)

 

  • Content-Type

클라이언트가 서버에 보내는 데이터의 유형을 정의한다.

 

ex) Content-Type: application/json(=> 나 서버한테 json형식으로 보낼거야), Content-Type: text/html(=> 나 서버한테 HTML형식으로 보낼거야)

 

  • Authorization

클라이언트가 서버에 인증 정보를 보낼 때 사용한다.

일반적으로 Bearer 토큰이나 Basic 인증 정보를 담고 있다

 

ex) Authorization: Bearer <token>

  • Content-Length

요청 본문의 크기(바이트 단위)를 지정한다.

POST 요청에서 본문을 전송할 때 유용하다.

 

ex) Content-Length: 1234

  • Cookie

클라이언트가 이전에 서버로부터 받은 쿠키를 요청에 포함하여 전송한다.

 

ex) Cookie: sessionid=abcd1234

 

헤더를 구성해본다면 

Host: www.example.com
User-Agent: Mozilla/5.0
Accept: application/json
Authorization: Bearer <token>

와 같이 구성할 수 있다.

 

그리고 다음 본문이 들어가기전에 중간에 헤더와 본문을 구분하기 위한 빈줄이 하나가 추가된다

 

본문(Body)

본문은 요청에 실제 데이터를 포함하는 부분으로, 주로 POST, PUT, PATCH 메서드에서 사용된다.

본문은 클라이언트가 서버로 전송하려는 데이터를 담고 있는다.

본문의 내용은 Content-Type 헤더에 의해 정의된 형식에 맞춰줘야 한다.

 

예를 들어서, POST 요청에서 JSON 데이터를 보내는 경우는 

{
  "username": "user1",
  "password": "password123"
}

와 같이 구성하고 HTML 폼 데이터를 보내는 경우는 

username=user1&password=password123

 

요청라인, 헤더, 본문이 합쳐진 하나의 예를 보면 

POST /login HTTP/1.1
Host: www.example.com
Content-Type: application/json
Content-Length: 47

{
  "username": "user1",
  "password": "password123"
}

와 같이 구성한다.

이는 POST 요청으로 /login이라는 URI로 HTTP/1.1 버전으로 요청을 보내고 그 요청은 www.example.com에서 보낸 요청으로 json형식으로 본문을 작성해서 보낼 것이고 해당 컨텐츠의 길이는 47바이을 넘지 않을 것이다. 

라고 요청을 보낸다.

 

GET요청의 경우는 본문이 없기 때문에 

GET /products HTTP/1.1
Host: www.example.com
User-Agent: Mozilla/5.0
Accept: text/html

 

05. HTTP Status Codes

HTTP 상태 코드는 서버가 클라이언트의 요청을 어떻게 처리했는지를 나타내는 3자리 숫자 코드이다

상태 코드는 서버가 요청을 처리한 결과를 클라이언트에게 알리기 위해 사용되며, HTTP 응답의 상태 라인에 포함되어 있다.

 

상태 코드는 세 자리 숫자로 이루어져 있으며, 첫 번째 숫자는 해당 상태 코드가 속하는 범주를 나타낸다.

 

상태 코드의 구조

상태 코드는

<HTTP 버전> <상태 코드> <상태 메시지>

로 구성되어 있고 상태 코드가 반환되는 예시로 

HTTP/1.1 200 OK

이렇게 HTTP/1.1 버전을 사용하고 상태코드는 200으로 해당 코드는 OK라는 메세지를 담고 있다.

 

상태코드의 첫번째 숫자는 상태코드의 범주를 나타내는데 이는 1 부터 5까지의 5가지 범주로 나뉜다.

  • 1xx (정보 응답 - Informational responses)

이 범주의 상태코드는 클라이언트가 보낸 요청을 서버가 받아 처리하고 있음을 알리는 정보성 메세지로 실제 응답 내용은 포함되지 않는다.

 

- 100 Continue : 클라이언트가 요청을 계속해서 보내도록 허용하는 상태코드, 요청 본문을 전송하기 전에 이 응답을 기다릴 수 도 있다

- 101 Switching Protocols : 서버가 요청에 따라 프로토콜을 변경했음을 나타낸다.

 

  • 2xx (성공 - Successful responses)

이 범주는 클라이언트의 요청이 성공적으로 처리되었음을 나타낸다.

요청이 성공적으로 처리되었을 때 이 상태 코드가 반환된다.

 

- 200 OK : 요청이 성공적으로 처리되었고, 응답 본문에 요청된 리소스가 포함된다.

- 201 Created : 요청이 성공적으로 처리되어 새로운 리소스가 생성되었음을 나타낸다.

- 204 No Content : 요청은 성공했지만, 반환할 콘텐츠가 없다는 의미이다.

 

  • 3xx (리다이렉션 - Redirection)

이 범주는 클라이언트가 요청한 리소스를 찾지 못했을 때, 다른 리소스로 리다이렉션해야 함을 나타낸다.

클라이언트는 이 코드를 받아서 다른 URI로 재요청을 해야한다.

 

- 301 Moved Permanently: 요청한 리소스가 영구적으로 다른 URL로 이동했음을 나타낸다. 클라이언트는 이후 해당 URL로 요청을 보내야 한다

- 302 Found : 요청한 리소스가 임시로 다른 URL로 이동했음을 나타낸다. 클라이언트는 이후에도 원래 URL로 요청을 보낼 수 있다.

- 304 Not Modified : 클라이언트가 요청한 리소스가 이전에 캐시된 버전과 변경되지 않았음을 나타낸다. 클라이언트는 캐시된 데이터를 사용한다.

 

  • 4xx (클라이언트 오류 - Client errors)

이 범주는 클라이언트가 잘못된 요청을 보냈을 때 발생하는 상태 코드이다.

클라이언트는 요청을 수정해야 할 필요가 있다.

 

- 400 Bad Request : 서버가 요청을 이해할 수 없거나 잘못된 문법이 포함되어 있을 때 발생한다.

- 401 Unauthorized : 요청한 리소스에 대한 인증이 필요함을 나타낸다. 클라이언트는 유효한 인증 정보를 제공해야 한다

- 403 Forbidden : 서버가 요청을 이해했지만, 클라이언트가 해당 리소스를 접근할 권한이 없을 때 발생한다.

- 404 Not Found : 요청한 리소스를 서버에서 찾을 수 없을 때 발생한다.

- 405 Method Not Allowed : 요청한 HTTP 메서드가 해당 리소스에서 허용되지 않을 때 발생한다.

 

  • 5xx (서버 오류 - Server errors)

이 범주는 서버가 요청을 처리하는 데 문제가 발생했을 때 반환된다.

클라이언트의 요청은 올바르지만, 서버 내부에서 문제가 발생한 경우이다.

 

- 500 Internal Server Error : 서버가 요청을 처리하는 동안 예기치 않은 오류가 발생했을 때 발생한다

- 502 Bad Gateway : 서버가 요청을 다른 서버로 전달하려고 했으나, 그 과정에서 오류가 발생한 경우이다.

- 503 Service Unavailable : 서버가 과부하 상태거나 일시적인 오류로 인해 요청을 처리할 수 없을 때 발생한다.

- 504 Gateway Timeout : 서버가 다른 서버로부터 응답을 기다리고 있는 동안 시간 초과가 발생한 경우이다.

 

이는 몆가지 자주 보게되는 코드의 예시를 달아 놓은 것으로 사실은 여러가지 에러들이 있으니 그때 그때 마다 찾아보면서 대처하도록 하자.

06. 웹 서버 생성하기

이제 웹서버를 한번 생성해보도록 하자.

Node.js에는 기본적으로 http 모듈이 포함되어 있기에 이걸 사용해서 간단하게 웹서버를 생성해보도록 하자.

 

먼저 server.js라고 파일을 하나 생성해주자.

그리고 require을 사용해서 http 모듈을 가져와주자.

그리고 서버를 생성해주기 위해서 createServer 메서드를 사용해서 서버를 생성해주자.

그리고 이 createServer 메서드의 설명에서 보이듯 

전달인자로 requestListener를 넣어주자.

더보기

createServer의 requestListener는 Node.js의 HTTP 모듈에서 서버가 클라이언트로부터 요청을 받을 때 실행되는 콜백 함수로 http.createServer() 메서드에 전달되며, 모든 HTTP 요청(Request)을 처리하고 응답(Response)을 반환하는 핵심 역할을 한다.

 

이 requestListener는 두 가지 매개변수를 가지는데

 

1. req(IncomingMessage 객체) - 클라이언트의 요청에 대한 정보를 담고 있고, 요청 메서드(GET, POST등), 요청 URL, 헤더, 바디 등의 정보를 확인할 수 있다.

 

2.res(ServerResponse 객체) -  서버가 클라이언트에 응답할 때 사용하는 객체로 응답 상태코드, 헤더, 본문 데이터를 설정하고 전송할 수 있다.

 

RequestListener는 req객체를 사용해서 요청을 확인해서 처리하고, req객체를 통해서 클라이언트에게 응답 데이터(상태코드, 본문)를 보낸다

그리고 이제 응답을 만들어볼 건데 res객체의 writeHead라는 메서드를 통해서 상태코드와 응답 헤더를 작성해주자.

writeHead의 첫번째 매개변수로는 상태코드를 작성해주고

두번째 인자로는 key-value의 형태로 응답해더를 추가해주자.

추가할 응답 헤더는 content-type으로 우리가 응답, 즉 반환할 데이터의 타입을 작성해서 보내주는 것으로 우리는 단순하게 text를 응답해줄 것이기 때문에 text/plain으로 설정해주자.

 

그리고 이 응답에 대한 연결을 종료하고 클라이언트로 데이터를 전송하기 위해서 res의 end 메서드를 사용해주자.

이 end 메서드는 응답 스트림을 종료하고 클라이언트로 데이터를 전송하는데, end 메서드 내부에 데이터를 넣어주면 해당 데이터가 클라이언트로 전송이 된다.

더보기

res.end([data], [encoding], [callback]); 

- 이 메서드는 서버가 응답 데이터를 보내는 마지막 단계에서 사용되며, 요청-응답 사이클을 종료한다.

 

data(옵션) - 클라이언트로 전송할 데이터, 문자열 또는 버퍼(buffer)형태로 전달해야 한다. 

encoding(옵션) - 전송할 데이터의 인코딩 형식이다, 기본값은 utf-8으로 되어 있다.

callback(옵션) - 응답이 종료된 후 호출되는 콜백함수이다.

 

여기까지가 서버를 구성하는 작업이였고 이제 이렇게 생성한 서버를 시작해주면 되는데 그때 사용되는 메서드는 listen이라는 메서드이다.

이 listen 메서드의 경우는 매개변수로 포트번호, 호스트네임, 백로드, 리스닝 리스너를 설정해줄 수 있는데 가장 먼저 

포트를 설정해주자.

 

port(필수) - 이는 해당 서버는 6500번 포트로 설정되어 시작되며 6500번 포트로 들어오는 요청은 해당 서버에서 처리하겠다는 의미로 필수적인 전달인자이다.

 

hostname(선택) - 서버가 바인딩될 호스트 이름(또는 ip주소)를 지정한다.

이 값의 기본값은 0.0.0.0으로 모든 네트워크 인터페이스에서 요청을 수신하게 된다.

특정 호스트를 저장하려면 추가적으로 설정해줘야만 한다.

이 때 특정 호스를 지정하는 것도 가능하다.

 

backlog(선택) 는 서버가 대기할 수 있는 연결 요청의 최대 수를 설정할 수 있는데 이 기본값의 경우는 운영체제마다 달라진다.

 

callback(선택) - 서버가 정상적으로 실행되었을 때 실행될 함수이다.

 

우리는 여기서 port와 callback만 사용해서 서버를 만들어보자

이렇게 포트는 6500을 설정해주고

콜백 함수를 하나 만들주고 내부에 해당 서버는 몆번 포트로 열렸는지 콜솔을 찍어주자.

이제 한번 서버를 실행해보면

그러면 바로 listen 함수에서 설정했던 콜백함수가 실행되고 

서버가 켜지면서 end로 전달했던 값을 출력하는 것을 볼 수 있다.

개발자도구를 열어서 response의 header를 보면 

이렇게 Content-Type이 text/plain으로 설정되어 있는 것을 확인할  수 있다.

 

만약 Content-Type을 application/json으로 변경하면 값을 어떻게 전달해야할까 ? 

end가 받을 수 있는 값의 형태는 문자열 혹은 버퍼이기 때문에 json형태를 문자열의 형태로 수정해서 전달해야한다.

json을 문자열로 바꿔주는 JSON.stringify()를 사용하고

그 내부에 json형태로 값을 전달 해주면 된다.

그러면 페이지에 접속하면 

이렇게 json데이터를 전송하는 것을 볼 수 있다.

 

07. HTTP Routing

HTTP 라우팅은 HTTP 서버를 생성한 후, 클라이언트로부터 들어오는 HTTP 요청의 URL과 HTTP 메서드(GET, POST 등)에 따라 요청을 처리하는 방식을 말한다.

 

쉽게 말하면 어떤 요청 메서드를 통해서 어디 URL로 요청을 줬는지에 따라서 그 요청을 처리하는 곳으로 분배시켜주는 것이라고 생각하면 된다.

 

이를 처리하는 방법은 사실 따로 함수를 사용하거나 하는 방식은 아니고 createServer의 콜백 함수의 내부에 로직을 추가하는 과정으로 라우팅을 설정해주는데 이를 위해서 IncomingMessage객체를 받는 req를 사용한다.

 

가장 먼저 req객체에서 URL을 뽑아내줘야 하는데 그 때 사용하는 것이 req의 url 이다.

req.url를 콘솔로 출력해보면 

브라우저에서 포트 다음 URL에

이런식으로 /test를 넣어주면 콘솔에서 

이렇게 경로를 찾아낼 수 있다.

 

이걸 통해서 A라는 url로 들어오면 A`로 보내고 B라는 url로 들어오면 B`로 보내질 수 있도록 분기를 넣어주는 것이다.

예시로 

이렇게 코드를 작성하면 /fstTest이라는 요청이 들어올때에는 fstTest라는 문자열 데이터를 내보내고 /sndTest라는 요청이 들어올 때는 sndTest라는 문자열 데이터를 내보낼 수 있도록 해줬다 결과를 보면 

원하는 대로 경로에 따라 다른 데이터를 반환 할 수 있도록 변경해줬다.

 

이렇게 설정해주는 것이 HTTP의 라우팅이란 기술이다.

08. Post 요청으로 데이터 추가하기

이번에는 요청을 post로 보내보도록 하자.

이전에 우리가 라우팅 했던 부분을 보면 

요청 메서드의 종류와는 상관 없이 모든 요청을 url을 통해서만 다르게 처리해주는 것을 볼 수 있다.

이번에는 메서드의 종류에 따라서 요청의 처리를 다르게 분기를 쳐주자.

이런 분기 처리를 위해 사용하는 것은 req의 method 속성이다.

이는 클라이언트에서 들어온 요청의 메서드가 어떤 것인지를 반환한다.

그럼 이 값을 가지고 가장 먼저 POST요청인지를 확인하고 

 

POST 이면서 change라는 경로로 들어올 때 

추가적으로 다른 로직을 정리해줄 수 있다.

 

만약 기존에 / 루트 경로로 접근했을때 

이렇게 json객체를 반환해줬다고 가정하고 추가로 post 요청을 / 루트 경로로 보냈을때 저 json 값에 c:c라는 값을 추가해주는 로직을 만들어 본다면 

먼저 이렇게 분기처리를 만들어주고 내부에 로직을 만들어 줘야 하는데 그 로직을 위해서 이해해야할 메서드는 req의 on 메서드와 Object의 assign 가 있다.

 

req.on() 

on 메서드는 이벤트 리스너를 등록하기 위해 사용된다.

더보기

on 메서드는 어떤 이벤트가 발생했을때 어떤 처리를 할지에 대해서 설정할 수 있는 함수인데 첫번째 매개변수로는 이벤트의 종류를 문자열로 설정하고, 두번째는 해당 이벤트가 발생하면 실행될 콜백함수를 지정하게 된다. 이 on 메서드가 받는 이벤트의 종류를 조금 알아보자면 

  • data 이벤트

요청 본문의 데이터가 스트림으로 도착할 때 발생한다.

그렇기에 데이터를 받아 처리하는데 사용된다.

 

사용의 예 

req.on('data', (chunk) => {
  console.log(`Received chunk: ${chunk}`);
});

전달 받은 데이터는 콜백함수의 매개변수로 전달되며 이를 사용해서 데이터를 조작할 수 있다.

또한 이 데이터는 일반적인 형태가 아니라 Buffer의 형태를 띄기에 내부에서 조작하기 위해선 .toString() 등의 변경과정이 필요하다.

  • end이벤트

모든 데이터 조각(chunk)이 전송되고, 데이터 스트림이 종료되었을 때 발생한다.

그렇기에 데이터 수신이 완료된 후에 수행할 후속 작업에 사용된다.

 

사용의 예

req.on('end', () => {
  console.log('Data transmission complete.');
});

 

  • error이벤트

요청 데이터를 처리하는 중에 에러가 발생할 경우 호출된다.

그렇기에 에러로그를 남기거나 클라이언트에 적절한 에러 응답을 보내기 위해 사용하고 에러가 발생할때 서버가 중단되지 않도록 안전하게 처리해줄 수도 있다.

 

사용의 예

req.on('error', (err) => {
  console.error(`Error occurred: ${err.message}`);
});
  • close이벤트

클라이언트와의 연결이 종료되었을 때 발생하는데 이는 데이터가 끝까지 수신되지 않은 상태에서도 발생할 수 있다.

그렇기에 요청-응답 주기의 종료 상태를 확인하거나, 정리 작업을 수행하기 위해 사용된다.

 

사용의 예

req.on('close', () => {
  console.log('Connection closed.');
});

 

 

Object.assign()

하나 이상의 소스 객체(Source Object)의 속성을 대상 객체(Target Object)에 복사한 후, 대상 객체를 반환하는 메서드이다

더보기

Object.assign의 원형은 

Object.assign(target, ...sources)

 의 형태를 띄는데 여기서 각각의 매개변수들의 의미는

 

target : 속성을 복사할 대상 객체

...sources: 속성을 복사할 소스 객체

 

이때 복사는 얕은 복사의 형태로 복사되기에 대상 객체(target)에 소스 객체들의 속성이 병합되며, target 객체 자체가 변경된다.

그리고 소스 객체의 속성이 대상 객체의 기존 속성을 덮어쓴다.

나중에 나열된 소스 객체의 속성이 더 우선순위를 가진다.

또한 이 Object.assign메서드의 반환값은 target 객체 자체가 반환된다.

const target = { a: 1, b: 2 };
const source1 = { b: 4, c: 5 };
const source2 = { d: 6 };

const result = Object.assign(target, source1, source2);

console.log(result); // { a: 1, b: 4, c: 5, d: 6 }
console.log(target); // { a: 1, b: 4, c: 5, d: 6 } (target이 수정됨)

 

*얕은 복사일 경우 복사하는 값이 2depth로 존재한다면(객체 내부에 객체가 존재하는 형태) 그 내부에 객체는 주소값(참조값)만 복사해서 갖고온다. 

그렇기에 복사된 객체의 2depth에 해당하는 값을 변경하면 원본 객체 또한 변경된다.

 

** 얕은 복사던 깊은 복사던 객체 내부에 객체가 존재하는 중첩된 객체의 형태가 아닌 경우, 즉 1 depth로만 되어 있는 형태의 객체라면 어떤 복사를 사용하던 독립된 객체로 생성할 수 있다.

이는 서로 어떠한 영향도 주지않는다는 의미이다.

 

이 두 함수를 사용해서 기존에 존재하던 {a : 'a', b: 'b'}의 객체에 c: 'c'를 추가해주자.

먼저 기존 객체를 전역변수로 설정해주고

 

그리고 post 메서드의 /에서 req.on메서드를 사용해서 요청을 처리할 것인데 

나중에 fetch 메서드를 사용해서 post요청의 body에 값을 전달해서 그 데이터를 여기서 받아 처리해줄 것이기 때문에 data 이벤트에 리스너로 등록해주자.

그리고 그 콜백 함수의 매개변수로 데이터가 전달되어 들어올 것이기 때문에 chuck라는 변수로 전달인자를 받아줄 매개변수를 설정한 콜백함수를 2번째 전달인자로 지정해주자.

먼저 console로 해당 데이터를 확인하기 위한 로그성 코드를 하나 추가해주고 

data이벤트로 받아오는 형태의 데이터는 Buffer 객체 형태로 되어 있게 된다.

그렇기에 이 값을 바로 사용할 수는 없고 toString() 메서드를 사용해서 문자열로 변경해주는 것이 가능하다.

정상저적으로 Buffer 객체가 문자열로 변경되었는지 코드를 추가해주자.

그리고 이제 Object.assign을 통해서 기존 값을 변경해줄 것인데 변경될 객체는 기존의 target을 넣어주고

두번째로는 변경시킬 데이터로써 전달될 데이터를 넣어주는데 해당 데이터는 문자열로 왔지만 json의 형태이기 때문에 parse라는 메서드를 통해서 객체의 형태로 변경해주자.

그러면 이제 브라우저의 개발자도구를 켜서 fetch 요청을 보내볼 것인데 

또 이제 fetch 요청이 뭔지를 확인해보자면 

 

fetch()

fetch는 JavaScript에서 네트워크 요청을 보내기 위한 API로 Promise 기반으로 작동하며, HTTP 요청을 보내고 응답을 처리하는 데 사용된다.

fetch는 기본적으로 GET 요청을 사용하지만, 다양한 HTTP 메서드(POST, PUT, DELETE 등)와 옵션을 설정하여 요청을 보낼 수 있다.

더보기

fetch 함수는 URL과 옵션을 인자로 받으며, 네트워크 요청을 보낸 후 Promise 객체를 반환한다.

이 Promise 객체는 요청이 완료되면 응답(Response) 객체를 반환한다.

fetch(url, options)
  .then(response => response.json())  // 응답을 JSON 형식으로 처리
  .then(data => console.log(data))    // 데이터를 처리
  .catch(error => console.error('Error:', error)); // 오류 처리

 

실 예시로는 

fetch('https://api.example.com/data')
  .then(response => response.json())  // 응답을 JSON 형식으로 변환
  .then(data => console.log(data))    // 데이터를 처리
  .catch(error => console.error('Error:', error)); // 오류 처리

 이렇게 사용한다.

 

이 fetch의 주된 옵션은 

 

  • method: 요청의 HTTP 메서드 (예: 'GET', 'POST', 'PUT', 'DELETE')
  • headers: 요청 헤더를 설정 (예: Content-Type, Authorization 등)
  • body: 요청 본문, 주로 POST, PUT 요청에서 사용
  • mode: 요청의 교차 출처 정책 (cors, no-cors, same-origin, navigate 등)
  • credentials: 쿠키 포함 여부 (same-origin, include, omit)

가 있다.

사용 방법은 해당 옵션을 순서대로 나열하는 형태로 두번째 전달인자로 key-value 형태(옵션명:옵션값)로 값을 전달한다.

fetch('https://api.example.com/data', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    name: 'John',
    age: 30
  })
})
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(error => console.error('Error:', error));

 

 

*일단 가볍게 이정도로만 알아둬도 이번 글에서 사용하기엔 차고 넘친다. 이 정도로만 알아보고 관심있다면 더 찾아서 공부해보도록 하자.

개발자도구에서 fetch를 통해 localhost:6500/에 POST 메서드로 body에 c:c라는 값을 담아 요청을 보내보도록 하자.

이 때 유의할 점은 body에 json객체를 전달해서 서버로 보낼 때에는 JSON.stringify를 통해서 json형태의 문자열로 전환해서 보내줘야만 한다는 것이다.

이렇게 변환하지 않고 보내면

해당 값을 처리하지 못하고 서버에서 에러를 벹는다.

이렇게 전환해서 보내면 

서버에서도 해당 값을 정상적으로 받아주고 브라우저를 새로고침해보면 

전역변수에 추가되었기에 서버가 켜져있는 상태에서 해당 객체의 값의 변화를 확인 할 수 있고 정상적으로 데이터가 전역변수로 추가된것을 알 수 있다.