백엔드 기본개념 정리

HS K·2022년 11월 9일
  1. 라우팅 (Routing)
    URI(또는 경로) 및 특정한 HTTP 요청 메소드(GET, POST 등)인 특정 엔드포인트에 대한 클라이언트 요청에 애플리케이션이 응답하는 방법을 결정하는 것
  • westudy : 유저 회원가입, 로그인 처리, 프론트엔드 측에서 요구하는 다양한 정보 응답 등 해당 자원에 대해 다른 함수(로직)을 실행하도록 하는 것

Express 공식 문서는 라우팅을 위와 같이 설명하고 있다. 쉽게 말하자면 "HTTP 요청의 method와 URI에 따라서 그 처리 로직을 구분하는 것, 또는 처리 함수를 달리하는 것"이라고 할 수 있다. 예를 들어보자

[예시-1]

// app.js
import express from 'express';

const app = express();

app.use('/api', apiRouter);


// auth.js
import { Router } from 'express';
const authRouter = Router();

authRouter.post('/signup', authController.signup);
authRouter.post('/signin', authController.signin);
  • express app을 생성하고, use 메소드를 통해 app 인스턴스에 authRouter 미들웨어를 바인딩한다.
  • authRouter는 post 메소드 요청 중, 지정된 path에 해당하는 응답(signup, signin)을 두 번째 인자에 등록한 미들웨어로 처리한다.

[예시-2]

const http = require("http");
const server = http.createServer((request, response) => {
  const { url, method } = request;

  if (method === "GET") {
    if (url === "/ping") {
      response.writeHead(200, { "Content-Type": "application/json" });
      response.end(JSON.stringify({ message: "pong" }));
    } else if (url === "/users") {
      response.writeHead(200, { "Content-Type": "application/json" });
      response.end(JSON.stringify({ users: users }));
    } else if (url.startsWith("/users")) {
      const userId = parseInt(url.split("/")[2]);
      const user = users.find((user) => user.id === userId);

      response.writeHead(200, { "Content-Type": "application/json" });
      response.end(JSON.stringify({ user: user }));
    } else if (url === "/posts") {
      response.writeHead(200, { "Content-Type": "application/json" });
      response.end(JSON.stringify({ posts: posts }));
    }
  } else if (method === "POST") {
    if (url === "/users") {
      let body = "";

      request.on("data", (data) => {
        body += data;
      });
      request.on("end", () => {
        const user = JSON.parse(body);

        users.push({
          id: user.id,
          name: user.name,
          email: user.email,
          password: user.password,
        });

        response.end("ok");
      });
    } else if (url === "/posts") {
      let body = "";

      request.on("data", (data) => {
        body += data;
      });
      request.on("end", () => {
        const post = JSON.parse(body);

        posts.push({
          id: post.id,
          name: post.title,
          content: post.content,
        });

        response.end("ok");
      });
    }
  } else if (method === "PATCH") {
    if (url.startsWith("/posts")) {
      let body = "";

      request.on("data", (data) => {
        body += data;
      });

      request.on("end", () => {
        const inputPost = JSON.parse(body);
        const postId = parseInt(url.split("/")[2]);
        const post = posts.find((post) => post.id === postId)

        post.title = inputPost.title;
        post.content = inputPost.content;

        response.writeHead(200, { "Content-Type": "application/json" });
        response.end(
          JSON.stringify({
            id: post.id,
            title: post.title,
            content: post.content,
          })
        );
      });
    }
  } else if (method === "DELETE") {
    if (url.startsWith("/posts")) {
      const postId = parseInt(url.split("/")[2]);
      const post = posts.find((post) => post.id === postId);
      delete post;

      response.writeHead(204, { "Content-Type": "application/json" });
      response.end(
        JSON.stringify({
          message: "NO_CONTENT",
        })
      );
    }
  }
});

server.listen(3000, "127.0.0.1", () {
  console.log("Listening to requests on port 3000");
});

위의 예시처럼 request 객체에서 url과 method 에 따라 각각의 경우를 조건문으로 분기하여 라우팅을 진행한다. 이 때 앱에서 의도한 다양한 로직(회원가입, 게시물 확인 등)을 처리해 주어야하고, ‘라우팅’은 아래의 내용과 같이 http method 별로 GET, POST, PUT, DELETE 등의 내용을 적절한 로직으로 안내해줌으로써 이루어진다.

따라서 라우터(Router)는 이름처럼 네트워크와 네트워크 간의 경로(Route)를 설정하고 가장 빠른 길로 트래픽을 이끌어주는 네트워크 장비라고 할 수 있다.


  1. 스코프(SCOPE)
    작성된 코드를 둘러싼 환경으로, 어떤 변수들에 접근할 수 있는지를 정의한다.
  • 전역 스코프 : 함수 안에 포함되지 않은 곳에 정의하는 것으로 코드 어디에서든지 참조할 수 있다.
  • 지역 스코프 : 함수 내에 정의된 것으로 정의된 함수 내에서만 참조할 수 있다.

출처 : https://edu.goorm.io/learn/lecture/557/%ED%95%9C-%EB%88%88%EC%97%90-%EB%81%9D%EB%82%B4%EB%8A%94-node-js/lesson/226443/%EC%8A%A4%EC%BD%94%ED%94%84%EC%99%80-%ED%98%B8%EC%9D%B4%EC%8A%A4%ED%8C%85

  1. 해시값
    임의의 길이를 갖는 임의의 데이터를 고정된 길이의 데이터로 매핑하는 단방향 함수를 말한다.
    쉽게 말해, 아무리 큰 숫자를 넣더라도 정해진 크기의 숫자가 나오는 함수이다.

ex) 어떤 숫자를 10으로 나누었을 때 그 나머지를 구하는 함수도 해시 함수이다. 왜냐하면 10으로 나눴을때 나머지는 0~9로 제한되어있기 때문이다.

해싱(hashing) : 해시 함수를 적용
양방향 암호화의 경우 암호화를 인코딩, 복호화를 디코딩이라 구별해서 부르지만 해시함수는 단방향이기 때문에 해싱이라는 용어는 암호화 과정만을 지칭한다.

  1. 레인보우 테이블(rainbow table)
    해시함수(MD-5, SHA-1, SHA-2 등)를 사용하여 만들어낼 수 있는 값들을 대량으로 저장한 표.
    보통 해시함수를 이용하여 저장된 비밀번호로부터 원래의 비밀번호를 추출해 내는데 사용된다

  2. parsing
    구문 분석이라고도하며 문장을 그것을 이루고 있는 구성 성분으로 분해하고 그들 사이의 위계 관계를 분석하여 문장의 구조를 결정하는 것이다.

  • 컴퓨터 과학에서 parsing은 일련의 문자열을 의미있는 token(어휘 분석의 단위) 으로 분해하고 그것들로 이루어진 Parse tree를 만드는 과정이다.
  1. JSON(JavaScript Object Notation)
    일반적으로 서버에서 클라이언트로 데이터를 보낼 때 사용하는 양식.

클라이언트가 사용하는 언어에 관계 없이 통일된 데이터를 주고받을 수 있도록, 일정한 패턴을 지닌 문자열을 생성해 내보내면 클라이언트는 그를 해석해 데이터를 자기만의 방식으로 온전히 저장, 표시할 수 있게 된다.

{
  "이름공간(키)": "값",
  "값 구분자": "각각의 값들은 ',' (콤마)로 구분되어야 합니다.",
     }
  1. nodemon
    Node에서는 코드에서 수정이 일어났을 때, 코드의 수정 사항이 서버에 자동으로 반영되지 않습니다. 즉, 코드를 수정하고나면, 서버를 계속 다시 켜주어야 하는데, 이를 보완하기 위하여 우리는 nodemon 이라는 패키지를 이용할 수 있습니다.

  2. CORS
    3세대 웹에서는 보안상의 이유로 서로 다른 출처의 http 통신을 막도록 기본적으로 세팅되어 있다. 그래서 동일한 출처의 주체끼리만 서로 통신할 수 있도록 하는 이 SOP(Same Origin Policy) 정책은 보안성 향상을 위한 기본이라 이해할 수 있습니다.

하지만 현실적으로 백엔드와 프론트 서버가 서로 다른 도메인에서 운용되는 현재의 3세대 웹 서비스 환경에서, 동일한 출처에서만 리소스를 주고 받을 수 없는 실정입니다. 따라서 이러한 SOP 정책을 올바르게 의도한 요청에 한해서 다소 완화시켜 서로간 통신을 가능케 해야하는데, 별도의 CORS 설정을 통해서 서로 다른 두개의 origin/domain 끼리의 데이터를 주고 받게 하기 위한 설정하여 이루어지며, 만일 해당 과정을 생략한다면 CORS 정책 위반을 이유로 웹 브라우저 차원에서 서버 통신을 막는다.

  1. 모듈
    미리 만들어둔 함수들의 집합. Node.js에서의 모듈은 2가지(코어 모듈, 파일 모듈)로 분류할 수 있으며 모듈(module)은 LEGO 블록에 비유할 수 있다.
    LEGO 블록은 독립적으로 각각 존재하지만 사용자가 조립하는 방법과 블록의 종류에 따라서 최종 결과물이 집도 될 수 있고, 차도 될 수 있고, 심지어 사람도 될 수 있는 것처럼 모듈도 독립적인 요소들의 조합을 통해 다양한 결과를 만들 수 있다.

    (1) 코어모듈 : Node.js에서 기본적으로 제공하는 모듈
    ex) http, fs

    (2) 파일모듈 : 코어 모듈을 제외한 모듈. 모듈을 직접 생성하기 위해서는 exports 객체를 사용하고, 모듈을 불러오기 위해서는 require() 함수를 이용한다.

  • 모듈의 종류
    Built-in module, Custom module, 3rd-party module로 나눌 수 있다.

    커스텀(Custom) 모듈은 Node.js CommonJS 방식으로 만들 모듈을 의미한다.

    빌트인(Built-in) 모듈은 Node.js가 설치되면서 기본으로 내장되어 있는 모듈들을 의미합니다. 대표적으로 모듈을 import 할 때 사용하는 require 함수도 빌트인 모듈입니다.

    마지막으로 3rd-party module은 다른 개발자들이 만들어 놓은 모듈을 의미한다.

  1. 파일 시스템(fs) : 파일을 읽고 쓰는 기능
    require() 함수를 사용해서 FS 모듈을 호출하면, 모듈 안에 우리가 사용할 수 있는 많은 함수들이 있는 객체가 반환되는데, 반환된 객체를 fileSystem 변수에 담아서 파일 시스템에 데이터를 읽고 쓰는 기능이 필요할 때마다 사용할 수 있게된다.
const fileSystem = require('fs')

const privateInformation = fileSystem.readFileSync("./privateInformation.txt", "utf-8");
console.log(`===== Before written ===== \n${privateInformation}`);

여기서, fileSystem.readFileSync() 메서드를 사용해서 파일에 접근하게 된다.
fileSystem.readFileSync()에 넘겨주는 첫번째 인자는 파일이 위치한 경로이고, 두번째 인자는 문자의 인코딩을 정의하기 위해서 필요한 인자입니다.

  1. Map 함수
    callbackFunction을 실행한 결과를 가지고 새로운 배열을 만들 때 사용한다.
     array.map(callbackFunction(currenValue, index, array), thisArg)```
  • currentValue : 배열 내 현재 값
  • index : 배열 내 현재 값의 인덱스
  • array : 현재 배열
  • thisArg : callbackFunction 내에서 this로 사용될 값

(예시)

const days = ["Mon", "Tue", "Wed", "Thus", "Fri"];

에서 days.map()을 실행하게 된다는 것은 days에 있는 모든 요일에 Function을 실행하고, Function에서 나온 값을 저장해서 새로운 배열로 만드는 것이다.

const smilmingDays = days.map(day => console.log(day));

여기에서 console.log(day)를 Return 하게 되는 것이다.
이렇게 되면 day가 배열의 각각의 값을 가지게 된다.

다른 예시로,

var numbers = [1,2,3,4,5,6,7,8,9];
var newNumbers = numbers.map(number =>number *2);
console.log(newNumbers);
  1. httpie

httpie는 CLI HTTP클라이언트이다. 우리가 일반적으로 사용하는 웹 브라우저가 가장 대표적인 클라이언트라고 할 수 있다. 웹사이트, 즉 웹 브라우저를 통해 들어가지 않고도 httpie라는 다른 클라이언트를 통해서 같은 정보를 얻어올 수 있는 것이다.

profile
주의사항 : 최대한 정확하게 작성하려고 하지만, 틀릴내용이 있을 수도 있으니 유의!

0개의 댓글