728x90
목차
1. HttpServer
- Node.js에 포함된 기능과 문법을 이용해서 웹호스팅을 할 수 있는 서버를 구축합니다.
1.1. http모듈을 require
- 서버 구축에 필요한 기능과 함수를 담고있는 'http모듈을 require'한다.
// 서버 구축에 필요한 기능과 함수를 담고있는 'http모듈을 require'한다.
const http = require('http');
1.2. createServer( )
- Node.js로 만든 http서버를 실행하는 함수.
- (req, res)=>{ } : 서버로 클라이언트의 요청이 있을 때 실행할 명령들이 들어간다.
- req, res를 전달받은 익명함수가 클라이언트로부터 들어온 요청에 응답한다.
http.createServer( (req, res) => {
// req는 요청을 받고, res는 응답을 한다.
res.write('<h1>Hello Node Server!!</h1>');
res.write('<h2>Welcome to my Node Server!!</h2>');
} )
.listen(8090, ()=>{ console.log('8090포트에서 서버가 대기중입니다.'); } );
- .listen(8090, ( ) => { } ) 에 있는 ' ( )=>{ } ' 는 서버가 시작되면 실행할 명령이 들어간다.
- 8090 : 클라이언트가 요청할 포트번호
1.3. http서버 - 에러처리
- createServer() 함수로 서버기능을 실행시킨다. + 에러처리 구문도 추가한다.
- createServer() 함수로 만든 '서버 객체를 server 변수에 저장'하고
기타설정은 server변수를 통해 별도로 실행한다. - server변수.on( ) 메서드로 서버에 관련한 여러가지 설정이 가능하다.
const http = require('http');
// create 서버함수로 서버기능을 실행시킨다. + 에러처리 구문도 추가한다.
// createServer 함수로 만든 서버 객체를 server 변수에 저장하고 기타설정은 server변수를 통해 별도로 실행한다.
const server = http.createServer((req, res)=>{
// 서버 요청시 응답내용이 쓰여진다.
res.write('<h1>Hello Node Server!!</h1>');
res.write('<h2>Welcome to my Second Server!!</h2>');
res.write('<h3>Welcome to my Node Server!!</h3>');
});
server.listen(8090, ()=>{
console.log('8090번 포트에서 서버 대기중입니다.');
}); // 포트번호(8090) 설정
// server.on('listening', ()=>{
// console.log('8090번 포트에서 서버 대기중입니다.');
// }); // 기타설정1 : 서버 실행시 동작
server.on('error', (error)=>{
console.error(error);
}) ; // 기타설정2 : 에러처리
1.4. 한 번에 여러 개의 서버를 실행
- createServer( )를 여러번 호출하는 방식
- 단, 두 서버의 포트번호를 다르게 지정해야 한다. (포트번호가 충돌하면 에러가 발생)
const http = require('http');
// 첫 번째 서버(8081 포트)
http.createServer((req, res)=>{
//응답 내용의 본문 전송
res.write('<h1>Hello Node Server #1</h1>');
//응답 내용의 마지막 전송 : res.end 실행 후에는 더 이상 응답내용이 전송될 수 없다.
res.end('<p>Hello Server!</p>');
}).listen(8081,()=>{ // 포트번호와 함께 이벤트 리스너 설정
console.log('8081번 포트에서 서버 대기중입니다!');
});
// 두 번째 서버(8082 포트)
http.createServer((req, res)=>{
res.write('<h1>Hello Node Server #2</h1>');
res.end('<p>Hello Server!</p>');
}).listen(8082,()=>{
console.log('8082번 포트에서 서버 대기중입니다!');
});
1.4.1. req, res
- request, response의 의미를 갖는 변수이다.
- 매개 변수이고, 서버에 있는 실제 request, response 객체가 전달된다.
- 매개 변수는 그 객체를 전달받아 사용하는 것으로 변수의 이름은 자유롭게 변경이 가능.
다만, 함수 내에서 변경된 이름을 일관되게 사용해주는 것이 중요하다.
1.5. http서버 - html 파일 표시
fs모듈을 활용해 html파일을 불러와 변수에 담고, res.end(변수)로 페이지에 표시한다!
const http=require('http');
const fs = require('fs').promises;
http.createServer(async (req, res)=>{
try{
const data = await fs.readFile('./04_Server.html');
// 헤더에 필요한 내용을 실어서 보내는 역할. 현재는 한글을 위한 속성이 담겨있다.
// 따라서 한글 인코딩을 위한 헤더 내용을 먼저 보내준다.
res.writeHead(200,{'Content-type' : 'text/html; charset=utf-8'});
res.end(data);
// write(일반전송), writeHead(헤더 내용 전송), end(전송 후 종료를 위한 함수)
}catch(err){
console.error(err);
res.writeHead(500,{'Content-type' : 'text/plain; charset=utf-8'});
res.end(err.message);
}
}).listen(8081, ()=>{
console.log('8081번 포트에서 서버 대기중입니다.');
} );
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>04_Server.html</title>
</head>
<body>
<h1>Node.js 웹서버 </h1>
<h2>만들 준비되셨나요?</h2>
</body>
</html>
1.5.1. writeHead()에 담는 html상태코드의 종류
- 2XX : 서버 전송 정상 완료.
- 3XX : 리다이렉션(다른페이지로 이동)을 알리는 상태
- 4XX : 요청 오류를 나타낸다. 요청 자체에 오류가 있을 때 표시된다.
- 5XX : 서버오류 - 요청은 제대로 왔지만 서버에 오류가 생겼을 때 발생한다.
1.6. http서버 - url 매핑
if( req.url === ' / '){ } 식으로 매핑하게 된다.
const http = require('http');
const fs = require('fs').promises;
let users = {}; // 입력폼에서 등록된 이름들이 담길 객체
http.createServer( async (req, res)=>{
try{
if(req.method=='GET'){ //조회(SELECT)용도로 쓰임
if(req.url === '/'){
//fs.readFile('./05_Front.html').then((data)=>{});
const data = await fs.readFile('./05_Front.html');
res.writeHead(200, {'Content-type':'text/html; charset=utf-8'});
return res.end(data); // return은 현재 위치에서 익명함수를 종료하는 것으로 이해하는 것이 편함
}else if(req.url==='/about'){
const data = await fs.readFile('./05_about.html');
res.writeHead(200, {'Content-type':'text/html; charset=utf-8'});
return res.end(data);
}else if(req.url ==='/users'){
// json 데이터 전송을 위한 헤더 설정
res.writeHead(200, {'Content-type':'application/json; charset=utf-8'});
//user 객체 안의 내용을 json 형식으로 변경하여 전송
return res.end( JSON.stringify(users) );
}
}else if(req.method=='POST'){ //로그인 또는 INSERT 용도로 쓰임
if(req.url === '/user'){
// req에 전송된 자료(name)을 Stream형식으로 받아 body변수에 넣는다.
let body = '';
req.on('data', (data)=>{ // {'name' : '홍길동'}
console.log('data : ', data.toString());
body+=data;
console.log('body : ', body);
});
// req.on(); : request의 동작을 첫 번째 인수로 전달된 키워드로 구분하여, 같이 전달된 익명함수를 실행한다.
// 'data' : 함께 전달된 자료 수신 및 처리
// 전달된 자료가 두 개 이상이여도 모두객체 형식으로 다 받아 처리한다.
return req.on('end', ()=>{
const {name} = JSON.parse(body); // 전달된 데이터의 값을 꺼내서 name 변수에 저장
const id = Date.now(); // id변수에 날짜를 추출(날짜 현재시간을 밀리초로 얻어낸 값)
users[id] = name; // 키값은 id, 밸류는 name으로 객체에 저장
res.writeHead(201, {'Content-Type':'text/plain; charset=utf-8'});
res.end('ok'); //원래 자리로 복귀
});
// 마지막 전송과 끝내기 위한 리턴.
// 단순히 req.end()만 실행되는 것이 아닌, 다른 동작이 함께 실행되어야 한다면 아래와 같이 익명함수를 'end'키워드와 함께 실행.
// 그 여러 실행들이 실행되고 리턴 & 종료된다.
}
}else if(req.method=='PUT'){ //특정 자료를 수정(UPDATE)할 때
// 요청내용 : axios.put('/user/'+key, {name});
// console.log(req.url); /user/151232355243
if(req.url.startsWith('/user/')){
const key = req.url.split('/')[2];
let body = '';
//data <- {name:실제전송된값}
req.on('data', (data)=>{
body += data;
});
return req.on('end', ()=>{
users[key] = JSON.parse(body).name;
res.writeHead(200, {'Content-Type':'text/plain; charset=utf-8'});
return res.end('수정 ok');
});
}
}else if(req.method == 'DELETE'){ //DELETE 용도로 사용
if(req.url.startsWith('/user/')){
const key = req.url.split('/')[2];
delete users[key];
res.writeHead(200, {'Content-Type':'text/plain; charset=utf-8'});
return res.end('삭제 ok');
}
}
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(8090, ()=>{ console.log('8090포트에서 서버가 대기중입니다.'); });
1.6.1. req.method의 종류
- req.method == 'GET' : 조회(SELECT)용도로 쓰임
- req.method == 'POST' : 로그인 또는 INSERT 용도로 쓰임
- req.method == 'PUT' : 특정 자료를 수정(UPDATE)할 때
- req.method == 'DELETE' : DELETE 용도로 사용
1.6.2. axios 라이브러리
- jquery와 같은 종류의 javascript 라이브러리
- http통신을 하는데 매우 인기있게 사용되는 라이브러리
- 브라우저와 Node.js 플랫폼에서 모두 사용가능
- 현재는 브라우저 상에서 사용하기 위해 src로 로딩했으며,
익스프레스 서버에서 사용하려면 설치명령으로 설치 후 사용한다. - json데이터 자동변환 기능이 있고, get, post, put, delete등 다양하게 구분하여 request요청이 가능하다.
- 일반적으로 form의 'submit이벤트를 이용하면 페이지 전환'이 일어난다.
( 전송 - 처리 - 새로운 페이지 로딩 )
페이지 전환 없이 등록 절차 실행 후 현재 위치로 되돌아오기 위해 'axios 객체를 이용'한다.
( 전송 - 처리 - 현재페이지로 복귀 )
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>05_Front.html</title>
<style type="text/css">
a{color:blue; text-decoration:none;}
</style>
<script src = "https://unpkg.com/axios/dist/axios.min.js"></script> // axios 라이브러리
</head>
<body>
<nav>
<a href="/">Home</a><br>
<a href="/about">About</a><br>
</nav>
<div>
<form id="form">
<input type="text" id="username">
<button type="submit">등록</button>
</form>
</div>
<div id="list"></div>
<!-- 스크립트를 이용한 이벤트 리스너는 head부분에 정의하면 실행에 오류가 많다, 따라서 지금처럼 body부분에 정의한다. -->
<script type="text/javascript">
// addEventListener : 클릭 또는 더블클릭 또는 현재의 form태그에서 있을 수 있는 submit과 같은 이벤트가 발생하면 전달인수로 전달된 익명함수를 실행해주는 함수(전달인수 : 이벤트 이름과 익명함수를 함께 전달해준다.) id가 form인 개체에 submit이벤트가 일어나면, (e)=>{} 익명함수가 실행된다. e변수에는 이벤트의 주인공인 form이 전달되어 함수가 실행된다.
// form이 submit되는 때를 잡아 실행될 이벤트 리스너 설정
document.getElementById('form').addEventListener('submit', async (event)=>{
// 현재 익명함수에서는 document.getElementById('form')을 부르기 위한 이름이 없으므로, 함수의 매개변수로 event를 만들고 이용한다.
// event <- document.getElementById('form')
event.preventDefault(); //form의 이벤트(submit)가 계속 진행되면 화면전환이 일어나므로, 이벤트동작(submit)을 멈춤
const name = event.target.username.value;
//alert(name);
if( !name ){
return alert('이름을 입력하세요');
}
try{
await axios.post('/user', {name});
// axios의 특성상 서버에서 보내오는 응답은 현재 위치로 응답되어져 복귀한다.
//const data = await axios.post('/user', {name}); <- 반환되는 값이 있을 경우 처리방법
//복귀 후 해야할 일 : 현재 등록된 user들을 조회해서 화면에 표시한다.
// 이름이 보여질 곳 : <div id="list"></div>
getUsers();
}catch(err){
console.error(error);
}
event.target.username.value = '';
});
async function getUsers(){
try{
// get 메서드 방식의 /users 요청 , 결과형식 json형식
const res = await axios.get('/users');
const users = res.data; // 요청에 대한 반환(리턴) 값을 객체 형식으로 변환 (키 : 값)
const list = document.getElementById('list');
list.innerHTML = '';
//users 변수에 있는 키값들을 전달인수로 하여 키값 개수만큼 반복실행
Object.keys(users).map( function(key){
// users에서 key값들을 추출 -> 각 key별로 function(key){}를 실행
// 추출된 키들 중 하나에 대해 실행될 함수.
// map에 의해 키 개수만큼 실행
const userDiv = document.createElement('div'); // div태그 생성
const span = document.createElement('span'); // span태그 생성
span.textContent = users[key]; // span태그 안에 키값으로 얻어낸 users값을 삽입
// 수정버튼 생성
const edit = document.createElement('button'); //<button></button>
edit.textContent = '수정'; // 버튼에 쓰여질 라벨
edit.addEventListener('click', async ()=>{
const name = prompt('바꿀 이름을 입력하세요'); //수정할 이름 입력
if(!name){
return alert('이름을 반드시 입력해야 합니다.')
}
try{
await axios.put('/user/' + key, {name});
getUsers();
}catch(err){
console.error(err);
}
});
// 삭제버튼 생성
const remove = document.createElement('button');
remove.textContent = '삭제';
remove.addEventListener('click', async ()=>{
try{
await axios.delete('/user/'+key);
getUsers();
}catch(err){
console.error(err);
}
});
userDiv.appendChild(span); // div안에 span 삽입
userDiv.appendChild(edit); // div안에 edit버튼 삽입
userDiv.appendChild(remove); // div안에 remove버튼 삽입
list.appendChild(userDiv); // div태그를 list 태그에 삽입
} );
}catch(err){
}
}
window.onload = getUsers;
</script>
</body>
</html>
addEventListener() :
- 클릭 또는 더블클릭 또는 현재의 form태그에서 있을 수 있는 submit과 같은 '이벤트'가 발생하면 전달인수로 전달된 익명함수를 실행해주는 함수( 전달인수 : 이벤트 이름과 익명함수를 함께 전달해준다. )
- id가 form인 개체에 submit이벤트가 일어나면, ( e )=>{ } 익명함수가 실행된다.
'e변수'에는 이벤트의 주인공인 'form이 전달'되어 함수가 실행된다.
preventDefault() :
- form의 이벤트(submit)가 계속 진행되면 화면전환이 일어나므로, 이벤트동작(submit)을 멈춤
300x250