그럼에도 불구하고

👨‍💻

[Node.js] 응답 헤더 / 라우터 요청 / 요청 리디렉션 / 요청 분석 본문

Node.js/Node.js basics

[Node.js] 응답 헤더 / 라우터 요청 / 요청 리디렉션 / 요청 분석

zenghyun 2023. 1. 27. 22:46

 응답 헤더 / 라우터 요청 / 요청 리디렉션 / 요청 분석에 대해 알아보자

 

 

 

[ 응답 헤더 ]

const http = require('http'); // require 파일을 불러오는 방법 

const server = http.createServer((req,res) => {

	res.setHeader('Content-Type', 'text/html');
    
}); // 서버를 생성할 때 꼭 필요한 메서드

 

res.setHeader란 뭘까?

setHeader의 경우 새로운 헤더를 설정하는 것을 말한다. 예를 들면 Content-Type은 브라우저가 알고 이해하며 받아들이는 디폴트(default) 헤더이며, 인수로 setHeader 안에 이 헤더 키에 대응하는 값을 설정하고 text/html에 전송하거나 설정할 수 있다. 

 

이렇게 되면 응답에 헤더를 붙이게 되고, 응답의 일부가 될 콘텐츠 유형은 HTML이라는 일련의 메타 정보를 전달하는 것이다.

 

 

 

[ 라우터 요청, 요청 리디렉션 ]

 

더보기
const http = require('http'); // require 파일을 불러오는 방법 
// ./:  상대경로 /: 절대경로 

const fs = require('fs');


const server = http.createServer((req, res) => {
  const url = req.url;
  const method = req.method;

  if (url === '/') {
    res.write('<html>');
    res.write('<head><title>Enter Message</title></head>');
    res.write('<body><form action="/message" method="POST"><input type ="text" name="message"><button type="submit">Send</button></form></body>');
    res.write('</html>');
    return res.end();
  }

  if (url === '/message' && method === 'POST') {
    fs.writeFileSync('message.txt', 'DUMMY');
    res.statusCode = 302;
    res.setHeader('Location', '/');
    return res.end();
  }
  res.setHeader('Content-Type', 'text/html');
  res.write('<html>');
  res.write('<head><title>My First Page</title></head>');
  res.write('<body><h1>Hello from my Node.js Server!</h1></body>');
  res.write('</html>');
  res.end();
}); // 서버를 생성할 때 꼭 필요한 메서드 

server.listen(3000);

 

 

 res.setHeader('Content-Type', 'text/html');
  res.write('<html>');
  res.write('<head><title>My First Page</title></head>');
  res.write('<body><h1>Hello from my Node.js Server!</h1></body>');
  res.write('</html>');
  res.end();

http.createServer를 통해 서버를 생성하면 기본적으로 응답을 전송하기 위해 작성할 html 내용을 말한다. 

 

위의 조건문들을 제거하고 서버를 열고 들어가 보면 

 

내가 작성한 내용을 웹 사이트에서 볼 수 있다. 

 

 

if (url === '/') {
    res.write('<html>');
    res.write('<head><title>Enter Message</title></head>');
    res.write('<body><form action="/message" method="POST"><input type ="text" name="message"><button type="submit">Send</button></form></body>');
    res.write('</html>');
    return res.end();
  }

 

localhost:3000과 localhost:3000/은 같다. /뒤에 올 내용은 위의 코드의 경우 form대그 안에 있는 button을 누르게 되면 보낼 페이지 즉 localhost:3000/message를 나타내게 된다.

 

 

위에서 url이 /일 경우에 대한 조건문이 성립하기 때문에 text를 입력할 수 있는 공간과 Send button이 있는 HTML 파일이 열리게 된다. 

 

여기서 버튼을 누르게 되면 localhost:3000/message의 주소로 넘어가게 된다. 

 

 

★ 조건문 안에서 return을 해야 하는 이유

조건문을 중단하기 위함으로 이 코드 앞에서 반환하여 함수 실행을 종료하게 만드는 것이다.

return을 반드시 작성해줘야 하는 이유는 res end 이후에는 다른 res.write나 res.set 헤더를 호출하면 안 되기 때문이다.

 

 

 if (url === '/message' && method === 'POST') {
    fs.writeFileSync('message.txt', 'DUMMY');
    res.statusCode = 302;
    res.setHeader('Location', '/');
    return res.end();
  }

 

url이 /message로 끝나면서 method 방식이 POST에 해당할 경우 message.txt라는 텍스트 파일을 만들고 그 안에 DUMMY라는 내용을 작성한다. 

 

이때 redirect 방식은 302를 이용하여 이 작업을 마치면 다시 localhost:3000/ 페이지로 돌아가게 된다.

 

※ 302 redirect 

https://despiteallthat.tistory.com/130

 

Http 301 / 302 Redirect의 차이

Http 301과 302 Redirect의 차이를 알아보자. HTTP Response Status Code는 요청에 대한 웹서버의 응답을 나타내는 코드를 말한다. 이 코드를 바탕으로 웹브라우저나 검색엔진 크롤러는 요청을 어떻게 처리해

despiteallthat.tistory.com

 

 

 

 

 

 

 


 

[ 요청 분석 ]

이번에는 text 박스에 내가 작성한 내용을 실제로 message.txt 파일에 저장해 보자. 

 

더보기
const http = require('http'); // require 파일을 불러오는 방법 

const fs = require('fs');

const server = http.createServer((req, res) => {
  const url = req.url;
  const method = req.method;

  if (url === '/') {
    res.write('<html>');
    res.write('<head><title>Enter Message</title></head>');
    res.write('<body><form action="/message" method="POST"><input type ="text" name="message"><button type="submit">Send</button></form></body>');
    res.write('</html>');
    return res.end();
  }

  if (url === '/message' && method === 'POST') {
    const body = [];
    req.on('data', (chunk) => {
      console.log(chunk);
      body.push(chunk);
    });
    req.on('end', () => {
      const parsedBody = Buffer.concat(body).toString();
      console.log(parsedBody);
      // input name을 message라고 지어서 message= 출력된다. 
      const message = parsedBody.split('=')[1];
      fs.writeFileSync('message.txt', message);
    });

    res.statusCode = 302;
    res.setHeader('Location', '/');
    return res.end();
  }
  res.setHeader('Content-Type', 'text/html');
  res.write('<html>');
  res.write('<head><title>My First Page</title></head>');
  res.write('<body><h1>Hello from my Node.js Server!</h1></body>');
  res.write('</html>');
  res.end();
}); // 서버를 생성할 때 꼭 필요한 메서드 

server.listen(3000);

 

 

if (url === '/message' && method === 'POST') {
    const body = [];
    req.on('data', (chunk) => {
      console.log(chunk);
      body.push(chunk);
    });
    req.on('end', () => {
      const parsedBody = Buffer.concat(body).toString();
      console.log(parsedBody);
      // input name을 message라고 지어서 message= 출력된다. 
      const message = parsedBody.split('=')[1];
      fs.writeFileSync('message.txt', message);
    });

    res.statusCode = 302;
    res.setHeader('Location', '/');
    return res.end();
  }

 

 

※ req.on()

req의 Event Listener 중 하나이며 on 메서드는 특정 이벤트를 들을 수 있게 한다. (listen) 

 

위의 코드에서는 text를 입력하고 Send button을 누르면 POST 방식으로 데이터를 보낸다. 

즉, 이 경우 듣고 싶은 이벤트는 data에 대한 이벤트인 것이다. 

 

=> IDE가 어떤 이벤트들을 들을 수 있는지 도움을 준다.

 


 

위의 코드에서 text에 data를 입력하면 새 청크(덩어리)가 읽힐 준비가 될 때마다 데이터 이벤트가 발생하는데 버퍼가 도움을 주는 것이다. 그 후에 두 번째 인자로 모든 데이터 이벤트에 실행될 함수를 넣는다. 

 

on(data)를 호출하면 리스너가 data 청크를 받도록 chunk를 입력하고 body라는 배열을 만들어서 body.push로 배열 안에 chunk를 넣는다.

 

req.on()은 요청에 대한 모든 데이터를 얻을 때까지 함수가 실행될 것이다. 내가 보낸 data가 한 번일 수도 있고, 여러 번일 수 있지만 모든 데이터를 얻어야 끝나게 된다.

 

 

※ end 리스너 

들어오는 요청 데이터 혹은 들어오는 전반적인 요청을 분석한 후에 발생한다.

마찬가지로 두 번째 인수로 정의하는 함수를 실행하는데 이 함수는 읽어 들인 모든 청크에 기반할 수 있다. 

 

이 청크와 상호작용 하기 위해서는 버퍼를 사용해야 한다. 

 

 

★ Buffer

더보기

데이터 스트림이란 무엇일까? 

 

스트림은 지속적인 프로세스를 말한다. 노드가 많은 양의 요청을 한 청크씩 읽고, 어느 시점이 되면 모든 요청을 다 읽게 될 것이다. 하지만 업로드된 파일의 경우 상당히 오래 걸릴 것이다. 

 

이럴 때는 데이터를 스트리밍 하면 디스크에 쓸 수 있게 되는데 데이터가 들어오는 와중에 앱이 실행되는 하드 드라이브나 노드 앱이 실행되는 서버에 쓸 수 있기 때문에 파일 전체가 분석 및 완료가 되고 전부 업로드되기까지 기다릴 필요가 없게 된다. 

 

Node.js는 요청이 크고 복잡하며, 미리 알지 못하기 때문에 전부 이런 방식으로 처리하는 것이다. 

 

하지만, 데이터를 미리 다룰 수도 있는데 문제는 코드를 사용해 청크를 마음대로 다룰 수는 없고 대신에 들어오는 청크를 체계화하기 위해 소위 말하는 버퍼를 이용하게 되는 것이다. 

 

버퍼는 버스 정류장과 비슷하다. 버스는 항상 달리지만 승객이 버스에 타고 내릴 수 있으려면 버스를 찾기 쉽도록 버스 정류장이 있어야 한다. 이게 바로 버퍼의 역할인 것이다. 여러 개의 청크를 보유하고 파싱이 끝나기 전에 작업할 수 있도록 하는 것이다. 

 

POST 메시지를 받을 때 응답을 보내거나, 파일에 쓰기 전에 요청 데이터를 받아야 할 때 사용하면 좋다.

 

parsedBody라는 버퍼에 toString을 호출해 문자열로 전환한다.  

 

이 과정까지 마치면 message.txt에는 "message=내가 입력한 내용"이 출력된다. input의 name을 message라고 지었기 때문에 'message='로 시작하는 것이다.

 

form은 모든 입력 데이터와 함께 자동으로 요청을 보내 요청 객체에 키-값 쌍으로 넣는다. 입력에 주어지는 이름이 키이며, 사용자가 입력하는 것이 값인 것이다.

 

새로운 상수 message를 만들고 parseBody.split에 등호를 넣은 후 결과 배열의 두 번째 요소인 인덱스 1을 요소로 두면 등호의 오른쪽 부분이 결과 배열에 들어갈 것이고 이제 비로소 내가 입력한 값만 message.txt에 적히게 된다.

 

 

 

 

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

[Node.js] 모듈 시스템 사용  (0) 2023.01.31
[Node.js] writeFile vs writeFileSync  (0) 2023.01.28
[Node.js] Node Life Cycle & Event Loop  (0) 2023.01.27
[Node.js] 서버생성  (0) 2023.01.26
[Node.js] 코드 실행방법  (0) 2023.01.25
Comments