[Node.js]http 모듈로 서버 만들기

UkiUkhui·2021년 11월 2일
0

node.js

목록 보기
2/2

1. 요청과 응답

  1. 요청 : 클라이언트가 서버에게
  2. 응답 : 클라이언트의 요청을 처리한 후 서버가 클라이언트에게
  • 서버 : 요청을 받는 부분, 응답을 보내는 부분 모두 존재해야 함.
const http = require("http");

//create a server object:
http.createServer((req, res)=>{});
  • http 모듈 사용 : http 서버 있어야 웹 브라우저 요청 처리 가능
  • createServer : http 모듈 내장 메서드
    * 인수 : 요청에 대한 콜백 함수(요청이 들어올 때마다 실행됨) == 콜백함수에는 응답을 적으면 됨
    *콜백의 매개변수 : 요청, 응답에 대한 객체

1.1. 응답을 보내고 서버에 연결하는 예제

const http = require("http");

http
  .createServer((req, res) => {
    res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
    res.write("<h1>Hello</h1>");
    res.end("<p>server</p>");
  })
  .listen(8080, () => {
    console.log("8080번 포트에서 대기중");
  });

코드 해석

1. listen 메서드

  • 첫 번째 인자 : 클라이언트에게 공개할 포트 번호
  • 두 번째 인자 : 포트 연결 완료 후 실행될 콜백함수
  • 파일 실행하면 서버는 해당 포트에서 오는 요청이 오길 기다림

2. res 객체

  • res.writeHead : 응답에 대한 정보 기록 == 헤더 부분
    * 첫 번째 인수 : 성공적인 요청임을 의미하는 200
    * 두 번째 인수 : 응답에 대한 정보를 보냄
    (콘텐츠 형식은 HTML, 한글 표시를 위해 charset은 utf-8로 설정)
  • res.write : 본문, 데이터가 기록되는 부분
    * 첫 번째 인수 : 클라이언트로 보낼 데이터
  • res.end : 응답을 종료하는 메서드
    * 인수 : 인수 존재 시 그 데이터도 클라이언트로 보낸 후 응답을 종료함.

    브라우저는 응답 내용을 받아서 렌더링함.

    • 웹 브라우저(클라이언트) > 요청 > Node.js 서버 내 등록한 콜백(~res.end()까지) > 응답으로 보냄

1.2. 이벤트 리스너 추가

const http = require("http");

const server = http.createServer((req, res) => {
  res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
  res.write("<h1>Hello</h1>");
  res.end("<p>server</p>");
});
server.listen(8080);

server.on("listening", () => {
  console.log("8080번 포트에서 서버 대기 중");
});
server.on("error", (error) => {
  console.error(error);
});
  • on(이벤트명, 콜백) : 이벤트 이름과 이벤트 발생 시 콜백 연결

1.3. fs 모듈을 통해 서버 실행

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

http
  .createServer(async (req, res) => {
    try {
      const data = await fs.readFile("src/server2.html");
      res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
      res.end(data);
    } catch (err) {
      console.error(err);
      res.writeHead(500, { "Content-Type": "text/html; charset=utf-8" });
      res.end(err.message);
    }
  })
  .listen(8080, () => {
    console.log("8080에서 대기");
  });
  • fs 모듈로 HTML 파일을 읽고 data 변수에 저장된 버퍼를 그대로 클라이언트에게 보냄.
  • 이전 예제와는 다르게 버퍼를 보낼 수 있음.

* HTTP 상태 코드

  • res.writeHead의 첫번째 인수로 상태코드를 넣으면 브라우저는 이걸 토대로 요청이 성공했는지 실패했는지 판단함.
  • 2xx : 성공을 알리는 상태코드
    * 200: 성공
    * 201: 작성됨
  • 3xx : 리다이렉션(다른 페이지로 이동)을 알리는 상태 코드. 어떤 주소를 입력했는데 다른 주소의 페이지로 넘어갈 때 사용
    * 301:영구 이동
    * 302:임시 이동
    * 304: 수정되지 않은 요청의 응답으로 캐시 사용
  • 4xx : 요청 오류. 요청 자체에 오류 있는 경우
    * 400 : 잘못된 요청
    * 401 : 권한 없음
    * 403 : 금지됨
    * 404 : 찾을 수 없음
  • 5xx :서버 오류, 예기치 못한 에러 발생 시 서버가 알아서 5XX대 코드를 보냄
    * 500 : 서버 내부 오류
    * 502 : 불량 게이트웨이
    * 503 : 서비스를 사용할 수 없음

2. REST와 라우팅 사용하기

  • 요청 : 주소를 통해 표현됨 > 서버가 이해하기 쉬운 주소여야 함.

2.1. REST(REpresentational State Transfer)

  • 서버의 자원을 정의하고 자원에 대한 주소를 지정하는 방법
  • 주소는 명사로 구성되는데 단순히 명사만 있으면 무슨 동작을 행하는지 알기 어려우므로 REST에서는 HTTP 요청 메서드를 사용함

2.1.1. HTTP 요청 메서드

1) GET

  • 서버 자원 가져오고자 할 때 사용.
  • 요청의 본문에 데이터를 넣지 않음
  • 데이터를 서버로 보내야 한다면 쿼리스트링 사용

2) POST

  • 서버에 자원을 새로 등록하고자 할 때 사용
  • 요청의 본문에 새로 등록할 데이터를 넣어 보냄

3) PUT

  • 서버의 자원을 요청에 들어 있는 자원으로 치환할 때 사용
  • 요청의 본문에 치환할 데이터를 넣어 보냄

4)PATCH

  • 서버 자원의 일부만 수정하고자 할 때 사용
  • 요청의 본문에 일부 수정할 데이터 넣어 보냄

5)DELETE

  • 서버의 자원을 삭제하고자 할 때 사용
  • 요청의 본문에 데이터를 넣지 않음

6)OPTIONS

  • 요청을 하기 전에 통신 옵션을 설명하기 위해 사용
  • 주소 하나가 여러 개의 요청 메서드를 가질 수 있음
    * GET 메서드의 /user 주소로 요청을 보냄 : 사용자의 정보를 가져오는 요청
    * POST 메서드의 /user 주소로 요청을 보냄 : 새로운 사용자를 등록
  • 주소와 메서드만 보고도 요청의 내용을 알아볼 수 있는 장점
  • GET 메서드 : 브라우저에서 캐싱할 수 있으므로 같은 주소로 GET 요청을 하면 서버가 아닌 캐시에서 가져올 수 있음.

2.1.2. HTTP 통신

  • 클라이언트가 누구든 상관없이 같은 방식으롤 서버와 소통 가능함
  • ios, 안드로이드, 웹, 다른 서버가 모두 같은 주소로 요청 보낼 수 있음
  • 서버와 클라이언트가 분리됨.
  • 서버 확장 시 클라이언트에 구애되지 않음.

2.2. RESTful한 웹서버 만들기

전체코드 참고(프론트엔드 포함)

restServer.js

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

http
  .createServer(async (req, res) => {
    try {
      console.log(req.method, req.url);
      if (req.method === "GET") {
        if (req.url === "/") {
          const data = await fs.readFile("src/restFront.html");
          res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
          return res.end(data);
        } else if (req.url === "/about") {
          const data = await fs.readFile("src/about.html");
          res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
          return res.end(data);
        }

        try {
          const data = await fs.readFile(`.${req.url}`);
          return res.end(data);
        } catch (err) {}
      }
      res.writeHead(404);
      return res.end("NOT FOUND");
    } catch (err) {
      console.error(err);
      res.writeHead(500, { "Content-Type": "text/plain; charset=utf-8" });
      res.end(err.message);
    }
  })
  .listen(8080, () => {
    console.log("8080에서 대기 중");
  });
  • req.method : HTTP 요청 메서드 구분
  • req.url : 메서드가 GET이면 요청 주소 구분함
  • 만약 존재하지 않는 파일 요청 시 혹은 GET 메서드의 요청이 아닌 경우 : 404 NOT FOUND 에러 응답함
profile
hello world!

0개의 댓글