본문 바로가기

교재 정리/Node.js

Lesson 5. 수신 데이터 다루기

5장에서 다룰 내용

  • 요청 데이터의 수집과 처리
  • curl 명령을 통한 POST 요청 제출
  • 기본 라우트를 가지는 애플리케이션 제작

 

5.1. 서버 코드의 수정

 

다음은 4장 코드를 수정 작업한 것이다.

const port = 3000,
        http = require("http"),
        httpStatus = require("http-status-codes"),
        app = http.createServer();

app.on("request", (req,res) => {
        res.writeHead(httpStatus.OK, {
                "Content-Type" : "text/html"
        });

        let responseMessage = "<h1>This will slow on the screen.</h1>";
        res.end(responseMessage);
});

app.listen(port);
console.log(`The server has started and is listening on port number: ${port}`);

 

- 다음 코드는 콜백 함수가 있는 server 객체를 가지고 있으며, 콜백 함수는 요청이 서버로 들어올 때마다 실행된다.

즉, 요청을 받을 때 서버는 요청 및 응답 객체를 실행할 함수가 들어 있는 코드에 전달한다.

 

- 우리는 수신하는 요청의 종류에 따라 콘텐츠를 변경시키는 것을 원할 것이다. 이를 위해 첫 번째 단계는 요청 헤더에서 어떤 HTTP 메소드와 어떤 URL을 사용할지 정하는 것이다. 


 

5.2. 요청 데이터의 분석

 

- 각 요청 객체는 rul 속성을 가지고 있으며, req.url 속성을 통해 클라이언트가 어떤 URL 요청을 하고 있는지 파악할 수 있다. 다음을 app.on("request") 을 실행해보자.

console.log(req.method);
console.log(req.url);
console.log(req.headers);

 

요청의 일부 개체는 다른 중첩 개체를 포함할 수 있기 때문에, JSON.stringify를 사용해 읽기 쉬운 문자열로 변환할 수 있다. (이 함수는 자바스크립트 객체를 인수로 사용해, 문자열을 반환한다.) 다음과 같이 코드를 변경하면 request 메소드를 출려력할 수 있다.

// getJSONsrting 함수
const getJSONString = (obj) => {
	return JSON.stringify(obj, null, 2);
}; 

// 출력
console.log(`Method: ${getJSONString(req.method)}`);
console.log(`URL: ${getJSONString(req.url)}`);
console.log(`Headers: ${getJSONString(req.headers)}`);

 

 

우리가 다룰 대부분의 요청은 GET 요청이다.

POST 요청을 한다면, 서버는 송신된 데이터를 처리하고 사용자에게 응답하여 데이터가 수신됐음을 알려야 한다.

 

- 누군가가 서버에 POST 요청을 하는 경우, POST의 내용(=서버에 전송되는 데이터)의 양을 알지 못하기 때문에, 데이터 청크를 통해서 http 서버로 들어오게 된다.

! 데이터 청크를 통해 스트리밍이 가능하다. 서버에 대량의 정보가 모두 도착하기를 바라는 대신, ReadableStream 라이브러리를 사용해 정보가 도착했을 때 해당 정보의 일부를 가지고 작업할 수 있다.

 

- req.on("data"): 특정 요청에 대한 데이터를 수신할 때 발생한다.

이 이벤트 핸들러 외부에서 새로운 배열 body를 정의하고, 서버에 도착할 때 순차적으로 데이터 청크를 추가해야 한다.

 

- 데이터 포스팅

  1. 클라이언트에서 서버로 포스팅한다.
  2. 데이터는 여러 가지 관리 가능한 청크 형태로 전송된다.
  3. 버퍼 객체로 서버는 각 데이터 청크를 수신한다. 수신된 데이터 청크는 서로 붙여 모아야 한다.
  4. 서버는 모은 데이터들을 원래의 형태로 만들고 클라이언트에 응답한다.
  5. 클라이언트는 데이터를 포스팅한 요청에 대한 결과를 돌려받는다.
app.on("request", (req,res) => {
    // 배열 생성
	var body = [];
    // 데이터 송신
	req.on("data", (bodyDate) => {
		body.push(bodyDate);
	});
    // 데이터 변환 및 출력
	req.on("end", () => {
		body = Buffer.concat(body).toString();
		console.log(`Request Body Contents: ${body}`);
	});
	
	console.log(`Method: ${getJSONString(req.method)}`);
	console.log(`URL: ${getJSONString(req.url)}`);
	console.log(`Headers: ${getJSONString(req.headers)}`);

	res.writeHead(httpStatus.OK, {
		"Content-Type" : "text/html"
	});

	let responseMessage = "<h1>This will slow on the screen.</h1>";
	res.end(responseMessage);
});

app.listen(port);
console.log(`The server has started and is listening on port number: ${port}`);

 

- app.on("request") 에 위의 새로운 요청 이벤트 핸들러를 추가해, 들어오는 데이터를 읽는다.

- 배열은 body로 만들어지고 참조된다. 수신된 데이터는 body 배열에 추가된다. 데이터 전송이 완료되면, 세 번째 콜백 함수가 실행된다.

- 마지막으로 body 배열을 텍스트 문자열로 변경하고 요청 내용을 콘솔에 출력한다.

 

! 데이터 제출을 위한 폼을 만들지 않았기 때문에, curl 명령을 사용해 확인한다.

- curl: 서버에 브라우저를 대신해서 요청을 보낼 수 있는 간단한 방법. 다양한 플래그 옵션을 사용할 수 있다.

- -d(--date): POST 방식으로 요청을 서버로 보내는 플래그.

curl -d "username=Jon&password=secret" http://localhost:3000

 

5.3. 웹 애플리케이션에 라우트 붙이기

 

- 라우트: 특정 URL을 위한 요청에 어떻게 애플리케이션에 응답해야 하는지 정의하는 방식.

라우트는 애플리케이션 로직에서 타깃이 될 수 있으며, 클라이언트로 보내는 정보를 특정 지을 수 있게 된다. 라우트를 만나는 것은 통합 애플리케이션 환경 구축에 꼭 필요하다.

 

const routeResponseMap = {
	"/info" : "<h1>Info Page</h1>",
	"/contact" : "<h1>Contact Us</h1>",
	"/about" : "<h1>Learn More about Us.</h1>",
	"/hello" : "<h1>Say hello by emailing us here</h1>",
	"/error" : "<h1>Sorry the page you are looking for is not here</h1>"
};

const port = 3000,
	http = require("http"),
	httpStatus = require("http-status-codes"),
	app = http.createServer((request, response) => {
		response.writeHead(httpStatus.OK, {
			"Content-Type" : "text/html"
		});

		if (routeResponseMap[request.url]) {
			response.end(routeResponseMap[request.url]);
		} else {
			setTimeout(() => {
				response.end("<h1>Welcome!</h1>");
			}, 2000);
		}
	});

app.listen(port);
console.log(`The server has started and is listening on port number: ${port}`);

 

- routeResposeMap 이라고 하는 응답을 위한 라우트를 생성한다.

- 요청 URL이 위에 있는 내용들과 일치하는지 체크하고, 그에 해당하는 헤더를 응답으로 보낸다. 

 

이 추가 코드로 각기 다른 URL에 따라 다른 콘텐츠로 응답을 줄 수 있다.

 

 

 

다음은 타이머를 건 라우트이다.

setTimeout(() => response.end(routeResponseMap[request.url]), 2000);

 

다음을 실행해보면 페이지 로딩에 걸리는 시간이 2초 정도 늘어났음을 알 수 있다.

명심할 점은 애플리케이션이 커질수록 웹 페이지의 응답 시간은 자연적으로 느려진다는 것이다.


 

5.4. 요약

 

1) 요청 콘텐츠에 따라 포스팅된 데이터를 처리할 수 있다.

2) 타킷 URL을 베이스로 요청 콘텐츠를 분리할 수 있다.

 

라우트를 작성하면 애플리케이션의 처리 로직이 구성된다. 애플리케이션이 확장됨에 따라 라우트 또한 확장되며, 전달할 수 있는 유형의 콘텐츠도 확장된다.