TIL - Server Side HTTP Transaction

김수지·2019년 12월 4일
0

TILs

목록 보기
13/39

Today What I Learned

Javascript를 배우고 있습니다. 매일 배운 것을 이해한만큼 정리해봅니다.


1. Client Side Review

  1. 함수형 프로그래밍 염두하고 코딩하기
    • application 운영에 필요한 요소들을 적어 본다.
    • 필요한 요소 나열 시 , 나 .가 나오는 대로 함수로 구분한 후 구현한다.
      → 함수의 성격을 명확하게 하고, 유지 보수 시 수정으로 인한 함수 간 영향도를 줄일 수 있음
    • init(혹은 첫 페이지 render) 시, 실행이 필요한 함수를 담아둔다.
  2. Web architect review
    • JS의 전통적인 run time은 browser였다.
    • 이제 JS의 run time을 OS로 옮겨서 server를 다룰 수 있다.(by Node.js)
    • 이제 browser에 client - server 간 요청과 응답 구조를 담아 spa 형태의 web application을 구축할 수 있다.
  3. form tag - preventDefault 사용
    • HTML에서 form tag 이용 시 preventDefault 실행은 왜 필요할까?
      예전에는 form 제출 후 html을 전달 받아 전체 페이지를 다시 보여줬던 패턴이 있었기 때문인 것 같다. 이제는 전체 페이지 refresh 없이도 페이지 내 비동기적 작업이 가능하므로 굳이 새로운 페이지를 re-load할 필요가 없다.

2. Server Side - Node.js 본격 시작

  1. Node.js : Chrome V8 자바스크립트 엔진으로 만든(compile) 자바스크립트의 런타임

  2. 이벤트 기반 논블로킹 I/O 모델: 유저가 버튼 클릭 등을 발생시켜 네트워크에 리소스를 요청하는 이벤트가 생길 때, 페이지 내 다른 기능과 상관 없이 비동기적으로 input을 보내고 output을 받는 모델

  3. CORS: Cross Origin Resource Sharing

    • 예전에는 서버로부터 클라이언트를 받아 구현을 했었다. 서버에서 주어진 정보이기 때문에 보안 상 문제를 두지 않았다.
    • 그런데 웹이 고도화 되면서 여러 곳의 리소스를 api를 통해 받아와 구현하는 것이 보편화되었고, 이제 클라이언트는 예전과 달리 1개 이상의 서버의 자원을 요청하고 응답 받아 사용하고 있다. (cross origin resource request)
    • 대부분 브라우저들은 이렇게 여러 군데에서 서버로부터 요청이 열리면 서버에 보안 상의 예상치 못한 일들이 발생할 것으로 여겨 cross origin resource request를 제한하고 있었다.
    • 그래도 많은 개발자들이 웹 앱 개선을 위해 cross domain request를 열어줄 것을 브라우저사에 요청했고, 이 과정을 걸쳐 해당 서비스가 허용하는 상황에서만 다른 도메인으로부터 요청을 받을 수 있도록 절충안을 만들었고 이것이 CORS이다.
      (개인적으로 난 이 이야기를 들으며 웹개발 환경 구축의 대서사시라고 느꼈다ㅎ)
  4. HTTP Method: OPTIONS

    • 앞서 말한 CORS를 실행하기 위해 허용의 범위에 대한 상세 정보를 기술하게 되었고, 이 부분에 대한 검증을 위해 HTTP method로 OPTIONS가 사용되고 있다.
    • 실제 서비스에 요청을 하기 전에 해당 서비스가 어떤 도메인을 허용하고 있는지, 어떤 http method를 허용하고 있는지, 헤더는 어떤 형식으로 허용하고 있는지에 대한 정보를 'preflight'에 담아 서로 확인하고 그 후에 실제로 요청을 넣는다고 생각하면 되겠다.
    • 암만 떠들어봐도 그림이 최고 image.png

3. 작은 서버를 구축해 HTTP transaction 익히기

  1. 어제 채팅방 형식의 client service를 만든 것에 이어 오늘은 node.js로 작은 규모의 로컬 server를 구축했다. 어제 만들었던 client의 server side 구축을 위한 예습? 정도였다.
    (예습이지만 node.js 공식 문서 보고 이해하고 작성하느라 엄청 헤맴 ㅜㅜ)
    client에서 문자를 적고 대문자로 혹은 소문자로 바꾸는 버튼 중 하나를 눌렀을 때 client에서 request를 보내고 server는 response를 해당하는 문자 형태로 변경하여 보내주는 형식의 인터페이스였다.

  2. 중점적으로 진행했던 부분

  3. 고전했던 부분

    • 런타임을 node로 옮긴 후 낯선 환경들: 콘솔 확인, 디버깅, 포트 열기, 서버 실행 등
      → 다음 번 server 구축에서는 package.json을 통해서 script 실행이나 dependencies 부분을 보완해야겠다. node.js에서의 디버깅 방법도 더 알아볼 예정이다.(to-do 1번).
    • client에서 문자열을 넘겨주더라도 중간에 JSON 형식으로 주고 받고 있으며, server에서 chunk of data로 변경된다는 점을 인지하면서 코드 짜기
      → client에서 HTTP body에 JSON 형식으로 담아 보내준 걸 봤으면서도 한참 동안 당연히 server side에서도 같은 형태의 값을 다룬다고 생각했다. node.js 공식 문서와 블로그 글들을 좀 더 읽어본 후에야 request, response 객체가 stream의 인스턴스라는 점을 인지할 수 있었다. eventEmmiter과 같은 개념과 용례를 살펴 보아야 했다. 다음부터는 문서 읽기에 좀 더 충분한 시간을 할애해야겠다.
  4. Code Review

    • express 등을 사용하지 않고(아니 아직 사용 할 줄 모르고) bare node.js를 구현해보는 것이 목표였고, 개념 이해를 위해 모든 과정을 단축하지 않고 구현해 코드가 엄청 길다. 아직은 별 수 없다. 빠르게 배워서 리팩토링해야지.
const http = require("http");

const PORT = 5000;
const ip = "localhost";
const defaultCorsHeader = {
  "access-control-allow-origin": "*",
  "access-control-allow-methods": "GET, POST, PUT, DELETE, OPTIONS",
  "access-control-allow-headers": "content-type, accept",
  "access-control-max-age": 10
};

const server = http.createServer((request, response) => {
  let headers = defaultCorsHeader;
  const { method, url } = request;
  let body = [];
  
//1. OPTIONS -> 204 status
  if (method === "OPTIONS") {
    response.writeHead(204, headers);
    response.end();
  }
  //2. POST이면서 upper거나 lower이면
  else if (method === "POST" && (url === "/upper" || url === "/lower")) {
    request
      .on("error", err => {
        console.error(err);
      })
      .on("data", chunk => {
        body.push(chunk);
      })
      //2-1. upperCase -> 대문자로 만들어서 파싱 200 status
      .on("end", () => {
        if (url === "/upper") {
          body = Buffer.concat(body)
            .toString()
            .toUpperCase();
        }
      //2-2. lowerCase -> 소문자로 만들어서 파싱 200 status
      else if (url === "/lower") {
          body = Buffer.concat(body)
            .toString()
            .toLowerCase();
        }
        //2-3. 값 자체가 빈 칸으로 들어오면? 400 에러
        if (body[2] === undefined) {
          response.writeHead(400, headers);
          response.end("eror");
        }
        response.writeHead(200, headers);
        response.end(JSON.stringify(body));
      });
  } //3. another request -> 400 에러
  else {
    response.writeHead(400, headers);
    response.end("eror");
  }
  response.on("error", err => {
    console.error(err);
  });

  console.log(
    `http request method is ${request.method}, url is ${request.url}`
  );
})
profile
선한 변화와 사회적 가치를 만들고 싶은 체인지 메이커+개발자입니다.

0개의 댓글