Node.js

Node.js - 수업 3일차

kakaroo 2022. 8. 24. 08:24
반응형

 

파이프


어떤 명령어의 결과 또는 출력을 다른 명령어의 입력으로 전송하는 개념

 

예를 들어 현재 디렉토리의 파일 갯수를 확인하려면..

1. 현재 디렉토리의 목록을 파일로 저장 ls > ls.txt

2. wc 명령어를 사용하여 ls.txt 파일의 단어를 카운팅 -> 파일의 갯수를 확인

3. ls.txt 삭제

 

 

 

//2_pipe.js
const fs = require("fs");
//파이핑(piping)- 스트림들을 연결하는 개념

//파이핑을 사용하여 복사를 수행하는 코드를 만들어 보자

//1. 복사를 위한 실습 파일을 생성, 이름은 hello.txt
//2. 파일 읽기를 위한 스트림을 생성
const rs = fs.createReadStream("./hello.txt");

//3. 파일 쓰기를 위한 스트림을 생성
const ws = fs.createWriteStream("./hello2.txt");

//4. 읽기 스트림을 쓰기 스트림에 연결
rs.pipe(ws);

 

//3_copy.js
const fs = require("fs");

//Node.js 8부터 파일 복사를 하기 위한 새로운 함수가 추가됨
fs.copyFile("hello.txt", "hello3.txt", (err) => {
	if(err) throw err;
	console.log("done!");
})

 

//4_dir.js
const fs = require("fs");

//1. 디렉토리 생성하기
const dirname = "./test";
if(!fs.existsSync(dirname)) {
	fs.mkdirSync(dirname);
}

//2. 디렉토리 내용 읽기
// ->해당 디렉토리의 존재 여부
const fnames = fs.readdirSync("."); //결과는 배열에 저장되어 반환
//console.log(fnames);
fnames.forEach((fname) => {
	console.log(fname);
})

//3. 디렉토리 삭제
//동기식 함수의 경우, 오류가 발생하면 예외를 발생시킨다
//이를 처리하려면 try ~ catch 를 사용하면 된다
try {
	fs.rmdirSync("./test");	// , {recursive: true});
	//								^-- 디렉토리가 비어있지 않은 경우 
    //									재귀옵션을 사용해야
}
catch(err) {
	console.log(err);
}

//4. 파일이름 변경
try {
	fs.renameSync("./hello.txt", "./hello1.txt");	
}
catch(err) {
	console.log(err);
}

 

 

<module 생성 및 사용>

//calc.js

const PI = 3.141592;
const square = X => X ** 2;

//모듈안의 요소들을 외부로 공개하려면 전역 객체의 exports 속성을 사용
module.exports = {
	PI,
	square
}

 

//5_module.js

//실습을 하기 위해 커스텀 모듈을 작성한다
//이 때, 커스텀 모듈의 이름은 'calc.js'로 한다.

const calc = require("./calc");	//확장자 생략 가능
console.log(calc.PI);

//ES2015+ 아래처럼 사용 가능
const { PI, square } = require("./calc");
console.log(PI);

 

HTTP 모듈

 

1. http: hyper text transfer protocol 의 약자로 하이퍼 텍스트를 전송하기 위한 프로토콜

2. 하이퍼 텍스트 : 하이퍼 링크(hyper link)라는 개념을 사용하여 논리적으로 연결된 문서

ex) HTML 문서

 

통신방법

HTTP 요청(request)과 응답(response)으로 통신

웹 브라우저 -> 주소 입력 -> 요청 -------> 웹서버 -> 응답 ----------> 웹 브라우저

 

 

 

 

 

 

 


포트

 


 

HTTP 서버 생성

//6_http.js
const http = require("http");

//1- Event Listener 방식

//hello world 서버를 구현
const server = http.createServer();

server.on("request",	//클라이언트로부터 요청이 왔을 때, 발생되는 이벤트
		 (req, res) => {
	//req: 클라이언트로부터 전송된 요청 메시지에 대한 객체
	//res: 클라이언트에게 전송할 응답 메시지 객체
	
	//응답코드 설정 : 가장 중요
	res.statusCode = 200;	//정상적으로 처리되었음을 의미하는 상태 코드
	
	//응답메시지 설정 : 굳이 안 써도 된다. 응답코드에 대한 부연설명이다.
	res.statusMessage = "OK";
	
	//전송할 데이터의 타입을 설정한다.
	res.setHeader("content-type", "text/plain; charset=utf-8");	//charset은 옵션, 쓰는게 좋다
	
	//데이터를 전송한다. 이 때, 전송전에 위의 응답헤더 보다 먼저 작성하면 오류(internal server error)가 발생한다.
	res.write("hello, world");
	
	//서버는 반드시 클라이언트에게 전송이 완료되었다는 것을 알려주어야 한다.
	//그렇지 않으면 클라이언트(브라우저)는 대기를 하게 되고, 결국 타임아웃이 발생한다.
	//res.end();	
	res.end("hello, world");	//데이터 전송 후 완료 <-- res.write 없이 짧은 데이터는 렇게도 가능
});

server.on("error",	//서버 내부에서 오류가 발생되었을 때 발생되는 이벤트
		  (err) => {
	console.log(err);
});

//서버를 실행
server.listen(8080);	//포트 번호
console.log("server running...");

 

서버 실행 (로컬 컴퓨터는 127.0.0.1:8080)

 

 

//6_http_callback.js
const http = require("http");
const fs = require("fs");
//1- Callback 방식

//hello world 서버를 구현
const server = http.createServer((req, res) => {
	/*
	res.statusCode = 200;
	res.statusMessage = "OK";
	res.setHeader("content-type", "text/plain; charset=utf-8");
	*/
	//상태코드와 컨텐트 타입을 한번에 설정 가능
	//res.writeHead(200, {"content-type": "text/plain; charset=utf-8"});
	//res.write("hello, world");
	
	//HTML코드를 전송하려면 컨텐트 타입을 html로 설정
	res.writeHead(200, {"content-type": "text/html; charset=utf-8"});
	//res.write("<h1>hello, world</h1>");
	res.end();
});

//서버를 실행
server.listen(8080);	//포트 번호
console.log("server running...");

//위 구조에서 문제점은 무엇인가?
//하나의 코드에 View와 Controller가 같이 있다.
//HTML : View(화면에 표현)
//JS : Controller(요청에 대한 응답처리)

 

MVC 관점에서 View와 Controller를 분리해야 한다.

<!-- index.html -->
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">		
	</head>
	<body>
		<h1>
			Hello, This is index.html
		</h1>
	</body>
</html>
const http = require("http");
const fs = require("fs");

http.createServer((req,res) => {
	res.writeHead(200, {"Content-type": "text/html; charset=utf-8"});
	res.write(fs.readFileSync("./index.html"));
	res.end();
}).listen(8080);

console.log("server running");

 


색인 index.html

웹 페이지 : 웹 서버안에 미리 작성되어 있는 문서 ex) HTML 문서(파일)

웹 사이트 : 웹 페이지들이 한 곳에 모여 있는 장소

인덱스 페이지 : 웹 사이트에 매번 처음으로 접속할 때마다 서버내의 파일을 보여주는 페이지

주소창에 www.naver.com  -> www.naver.com/index.html

:: 웹 사이트 방문자 처음으로 보게 되는 웹 페이지

 

 

path 에 따라 다르게 페이지를 로딩하는 예

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

http.createServer((req,res) => {
	res.writeHead(200, {"Content-type": "text/html; charset=utf-8"});
	console.log("url: ", req.url);
	if(req.url === "/")
		res.write(fs.readFileSync("./index.html"));
	else if(req.url === "/about")
		res.write(fs.readFileSync("./about.html"));
	else if(req.url === "/contact")
		res.write(fs.readFileSync("./contact.html"));
	else {
		res.write(fs.readFileSync("./error.html"));
	}
		
	res.end();
}).listen(8080);

console.log("server running");

 

위 코드의 문제..

새로운 페이지를 추가해야 하는 요구사항이 들어올 때마다 기존 코드를 계속 수정해야 한다. 즉, 유지보수가 어렵다.

 

const responseMap = {
	"/" : __dirname + "/index.html",
	"/about" : __dirname + "/about.html",
	"/contact" : __dirname + "/contact.html",
	"/error" : __dirname + "/error.html"
};

http.createServer((req,res) => {
	const url = req.url;
	console.log("url: ", url);
	if(responseMap[url]) {
		res.writeHead(200, {"Content-type": "text/html; charset=utf-8"});
		res.end(fs.readFileSync(responseMap[url]));
	} else {
		res.writeHeader(404, {"content-type": "text/html; charset=utf-8"});
		res.end(fs.readFileSync("./error.html"));
	}	
}).listen(8080);

 

Map 수정도 해야 하는 문제가 여전히 남아 있다.

//step3
const getViewPath = url => {
	if(url === '/') {
		url = "index";
	}
	return __dirname + `/${url}.html`;
}

http.createServer((req,res) => {
	const url = req.url;
	console.log("url: ", url);
	const viewPath = getViewPath(url);
	fs.readFile(viewPath, (err,data) => {
		if(err) {			
			res.writeHeader(404, {"content-type": "text/html; charset=utf-8"});
			res.end(fs.readFileSync("./error.html"));
		}
		res.writeHead(200, {"Content-type": "text/html; charset=utf-8"});
		res.end(data);
	});
}).listen(8080);
console.log("server running");

 


Input 방식

 

<!-- input.html -->
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">		
	</head>
	<body>
		<h1>
			GET METHOD
		</h1>
		<!--<form action="/process_data">
			<p> <input type=text name="title"> </p>
			<p> <textarea name="content"></textarea> </p>
			<p> <input type="summit"></p>
			<p> <button> 제출 </button> </p>
		</form>
		-->
		<form action="/process_data" method="GET">
			이름:<input type="text" name="uname"><br>
			나이:<input type="number" name="uage"><br>
			<button> 입력 </button>
		</form>
		
	</body>
</html>

파이썬 서버 실행

#python3 -m http.server

 

파이썬은 포트가 8000번으로 실행

위 input.html 실행 > 이름/나이 입력 -> 입력 버튼

아래처럼 GET 방식으로 처리가 됨

[24/Aug/2022 06:44:22] "GET /process_data?uname=23&uage=234 HTTP/1.1" 404

 

 


GET Method 의 param(query) 가져오는 예

//9_method.js

const http = require("http");
const fs = require("fs");
const url = require("url");
const qs = require("querystring");

http.createServer((req, res) => {
	//console.log(req);
	console.log(req.url);
	
	//req.url은 경로부터 시작되는 URL이다.
	//전체 URL을 가져오려면 아래와 같이 hostname + port 를 같이 넣어줘야 한다.
	const myUrl = new URL(req.url, "http://localhost:8080");
	
	if(req.url ==='/') {
		fs.readFile(__dirname + "/input.html", (err,data) => {
			res.writeHead(200, {"content-type": "text/html, charset=utf-8"});
			res.end(data);
		})
	}
//case 1		
	/*else if(url.parse(req.url).pathname === "/input.do") {
		//URL의 쿼리를 파싱하여 이름과 나이를 출력하는 코드를 구현해보세요.
		const parsed = url.parse(req.url);		
		const query = qs.parse(parsed.query);		
		console.log(query.uname, query.uage);
		
		res.writeHead(200, {"content-type": "text/html, charset=utf-8"});
		res.end(`${query.uname}, ${query.uage}`);
	}*/
//case 2	
	else if(myUrl.pathname === "/input.do") {
		const params = myUrl.searchParams;
		//console.log(params);	//URLSearchParams { 'name' => 'kakaroo', 'age' => '20' }
		console.log(params.get("uname"), params.get("uage"));	//kakaroo 20
		
		res.writeHead(200, {"content-type": "text/html, charset=utf-8"});
		res.end(`${params.get("uname")}, ${params.get("uage")}`);

	}
	
}).listen(8000);
반응형

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

Node.js - 수업 5일차  (0) 2022.08.26
Node.js - 수업 4일차  (0) 2022.08.25
Node.js - 수업 2일차  (0) 2022.08.23
Node.js - 수업 1일차  (0) 2022.08.22