블로그 내 코드 자료 출처
Node.js 교과서 개정2판(지음이 조현영)
myEvent.on
과 myEvent.addListener
는 동일하게 이벤트 리스너 등록 키워드이다.
const EventEmitter = require('events')
const myEvent = new EventEmitter()
myEvent.on('event1',() => {
console.log('이벤트1 발생!')
})
myEvent.on('event1', () => {
console.log('이벤트 1 추가 발생')
})
myEvent.once('event2', () => {
//이벤트를 한번만 발생하게 하는 .once 키워드
console.log('이벤트 2 발생')
})
myEvent.on('event3', () => {
console.log('event3 발생!!!')
})
myEvent.on('event3', () => {
console.log('event3 추가 발생!!!')
})
const listner = ('event4',() => {
console.log('event4 발!생!')
})
myEvent.on('event4',listner)
myEvent.emit('event1') //이벤트 발생기
myEvent.emit('event2')
myEvent.emit('event2')
myEvent.emit('event3')
myEvent.emit('event4')
myEvent.removeListener('event4',listner) //내가 추했던 listner를 삭제 가능하다.
myEvent.emit('event4')
myEvent.removeAllListeners('event3') // event3에 대한 모든 listner가 삭제된다.
myEvent.emit('event3')
// myEvent.addListener myEvent.on과 동일하다.
아래와 같이 함수 형태로 만들어주면 listner
명 수정에 따라 더욱 편하게 사용할 수 있다.
const listner = ('event4',() => {
console.log('event4 발!생!')
})
myEvent.on('event4',listner)
내가 추가했던 listner를 삭제 가능하다.
아래 줄의 emit은 반응 안한다.
myEvent.removeListener('event4',listner) //내가 추가했던 listner를 삭제 가능하다.
myEvent.emit('event4')
.removeAllListeners
로 모든 event listner를 삭제할 수 있다.
myEvent.removeAllListeners('event3') // event3에 대한 모든 listner가 삭제된다.
myEvent.emit('event3')
listner를 함수화 하여 만듬.
const listner = () => {
console.log('event4 발!생!')
}
myEvent.on('event4',listner)
익명 함수로(콜백형식) 만듬.
myEvent.on('event3', () => {
console.log('event3 추가 발생!!!')
})
아래 listnerCount()
를 사용하여 연결된 이벤트 갯수 파악이 가능하다.
console.log(myEvent.listenerCount('event3'))
강제적으로 서버 error를 발생 시켰다.
let i = 0
console.log('시작')
setInterval(() => {
if(i===5) {
throw new Error('서버를 고장내주마!')
} else {
console.log(i)
i++
}
}, 1000);
예외처리를 위해 try
catch
구문을 사용한다.
내가 error가 예상되는 부분을 try
로 감싼다. 사진과 같이 서버가 꺼지지 않고 계속 돌아감을 알 수 있다.
let i = 0
console.log('시작')
setInterval(() => {
try {
if(i===5) {
throw new Error('서버를 고장내주마!')
} else {
console.log(i)
i++
}
} catch(err) {
console.error(err)
}
}, 1000);
// let i = 0
// console.log('시작')
// setInterval(() => {
// try {
// if(i===5) {
// throw new Error('서버를 고장내주마!')
// } else {
// console.log(i)
// i++
// }
// } catch(err) {
// console.error(err)
// }
// }, 1000);
const fs = require('fs')
setInterval(() => {
fs.unlink('./abc.js', (err) => {
//두 번째 인자에 콜백으로 err처리를 하면 예외처리를 지원하는 함수도 있다.
//내부 처리임
//이런 기능을 모르면 try,catch를 사용해도 괜찮음
if(err) {
console.log(err)![](https://velog.velcdn.com/images%2Fansunny1170%2Fpost%2F2e01ffdf-845c-4105-932e-68dbfd99a919%2Fimage.png)
}
})
},1000)
const fs = require('fs').promises
setInterval(() => {
fs.unlink('./abc.js').catch(err => {
console.error(err)
})
}, 1000);
권장하는 방법은 아니나 에러 위치 파악이 어려울 때 사용한다.
최후의 수단으로 사용하고, 안쓸수록 좋다.
process.on('uncaughtException',(err) => {
console.error('예기치 못한 에러', err)
})
setInterval(() => {
throw new Error('서버를 고장 낼꺼야')
}, 1000);
setInterval(() => {
console.log('정상진행')
}, 1000);
http.createServer((request, response) =>{ })
서버를 만들기 위한 메소드
const http = require('http')
http.createServer((request,response) => {
response.writeHead(200,{'Content-Type' : 'text/html;charset=utf-8'})
//객체 형태로 기입하고 내용은 html형태로 받겠다라는 뜻이다. 그리고 utf-8형식으로 받겠다.
response.write('<h1> hello node! </h1>')
response.end('<p> hello server! </p>')
//end를 꼭 써야 응답을 끝낼 수 있다. 끝내면서 content를 또 전달 할 수 있다.
})
.listen(3000, () => {
console.log('포트 3,000번으로 실행하고 있음!')
})
다른사람의 IP를 통하여 접근도 가능하다.
cmd에서 ipconfig 입력하여 IPv4 에서 WIFI주소 확인 가능하다.
const http = require('http')
const server = http.createServer((request,response) => {
response.writeHead(200,{'Content-Type' : 'text/html;charset=utf-8'})
response.write('<h1> hello node! </h1>')
response.end('<p> hello server! 김예찬! </p>')
})
server.listen(3000)
server.on('listening',() => {
console.log('이벤트 리스너 방식으로 포트 3000번 포트에서 실행하고 있음')
})
server.on('error',(error) => {
console.error(error)
})
const http = require('http')
const server = http.createServer((request,response) => {
response.writeHead(200,{'Content-Type' : 'text/html;charset=utf-8'})
response.write('<h1> hello node! </h1>')
response.end('<p> hello server! 김예찬! </p>')
})
server.listen(3000)
server.on('listening',() => {
console.log('이벤트 리스너 방식으로 포트 3000번 포트에서 실행하고 있음')
})
server.on('error',(error) => {
console.error(error)
})
//server1 = 두 번째 서버
const server1 = http.createServer((request,response) => {
response.writeHead(200,{'Content-Type' : 'text/html;charset=utf-8'})
response.write('<h1> hello node1! </h1>')
response.end('<p> hello server1! 김예찬! </p>')
})
server1.listen(3001)
server1.on('listening',() => {
console.log('이벤트 리스너 방식으로 포트 3001번 포트에서 실행하고 있음')
})
server1.on('error',(error) => {
console.error(error)
})
<html>
<head>
<meta charset="utf-8">
<title>Nodejs 웹서버</title>
</head>
<body>
<h1> 만들준비 되었나?</h1>
<p> server 만들어 보자</p>
</body>
</html>
//async-await 방식
const http = require('http')
const fs = require('fs').promises
const server = http.createServer(async (req,res) => {
try{
const data = await fs.readFile('./index.html')
res.writeHead(200, {'Content-Type':'text/html; charset=utf-8'})
res.end(data)
} catch (err) {
console.error(err)
}
})
server.listen(3000)
server.on('listening', () => {
console.log('서버 3000번으로 실행하고 있음')
})
//.then 방식
const http = require('http')
const fs = require('fs').promises
const server = http.createServer((req,res) => {
const html = fs.readFile('./index.html')
html.then((data) => {
res.writeHead(200, {'Content-Type':'text/html; charset=utf-8'})
res.end(data)
}).catch((err) => {
console.error(err)
})
})
server.listen(3001)
server.on('listening', () => {
console.log('서버 3001번으로 실행하고 있음')
})
이렇게 에러메시지 띄우는 것을, 예외처리 혹은 error handling이라고도 한다.
//async-await 방식
const http = require('http')
const fs = require('fs').promises
const server = http.createServer(async (req,res) => {
try{
throw new Error('에러메시지 : 표시할 수 없는 화면입니다.') // 에러를 강제로 내보자
//에러를 강제로 내면 catch에 잡힌다. 위에 에러메시지가 catch(err)의 err로 전달이 된다.
const data = await fs.readFile('./index.html')
res.writeHead(200, {'Content-Type':'text/html; charset=utf-8'})
res.end(data)
} catch (err) {
console.error(err)
res.writeHead(500,{'Content-Type':'text/html; charset=utf-8'})
res.end(`<p>${err.message}</p>`)
//500 : 앞 인자는 응답코드다. 500번대는 서버 오류.
//오류 발생 시, 사용자에게 오류상황을 알려줘야한다.
//그럼 강제적으로 오류 발생을 어떻게 시킬까? 맨윗출 throw new Error이다.
}
})
server.listen(3000)
server.on('listening', () => {
console.log('서버 3000번으로 실행하고 있음')
})
Representational State Transfer 의 약자
코드로 보면
req.method
로 HTTP 요청 메서드를 구분하고 있다.
메서드가GET
이면 다시req.url
로 요청 주소를 구분한다.
주소가/
일 때는restFront.html
을 제공하고,
주소가/about
이면about.html
파일을 제공한다.이외의 경우에는 주소에 적힌 파일을 제공한다.
/restFront.js
라면restFront.js
파일을 제공할 것이고,
/restFront.css
라면restFront.css
파일을 제공할 것이다.
const http = require('http');
const fs = require('fs').promises;
const users = {}; // 데이터 저장용 db를 안쓰니 임시용으로 사용
http.createServer(async (req, res) => {
try {
console.log(req.method, req.url);
if (req.method === 'GET') { //GET요청이 왔을 때, 아래 3가지 요청이 있는 것이다.
if (req.url === '/') { // '/'는 라우터라고 하며,
const data = await fs.readFile('./restFront.html');
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
return res.end(data); //.end에 return을 붙여준 이유 p.184
} else if (req.url === '/about') {
const data = await fs.readFile('./about.html'); //about.html을 보여줘라!
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
return res.end(data);
} else if (req.url === '/users') {
res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' });
return res.end(JSON.stringify(users)); //users는 현제 객체 형태이다.
//JSON형식이니 문자형으로 바꿔줘!
}
// /도 /about도 /users도 아니면
try {
const data = await fs.readFile(`.${req.url}`);
return res.end(data);
} catch (err) {
// 주소에 해당하는 라우트를 못 찾았다는 404 Not Found error 발생
}
다른 HTTP 요청 메서드들을 추가하고, 데이터베이스 대용으로 users라는 객체를 선언하여 사용자 정보를 저장하였다.
POST /user
요청에서는 사용자를 새로 저장하고 있으며,PUT /user/아이디
요청에서는 해당 아이디의 사용자 데이터를 수정하고 있다.
DELETE /user/아이디
요청에서는 해당 아이디의 사용자를 제거한다.
POST와 PUT 요청을 처리할 때 조금 특이한 것을 볼 수 있다.
바로req.on('data')
와req.on('end')
의 사용이다.
요청의 본문에 들어 있는 데이터를 꺼내기 위한 작업이라고 보면 된다.
req와 res도 내부적으로는 스트림(각각 readStream과 writeStream)으로 되어 있으므로 요청/응답의 데이터가 스트림 형식으로 전달된다.
또한 on에서 볼 수 있듯이 이벤트도 달려 있다.
다만 받은 데이터는 문자열이므로 JSON으로 만드는 JSON.parse 과정이 필요하다.
} else if (req.method === 'POST') {
if (req.url === '/user') {
let body = '';
// 요청의 body를 stream 형식으로 받음
req.on('data', (data) => {
body += data;
});
// 요청의 body를 다 받은 후 실행됨
return req.on('end', () => {
console.log('POST 본문(Body):', body); //우측 body에 최종적으로 들어온다.
const { name } = JSON.parse(body); //좌측 name을 찾아서 구조분해할당을 했다.
const id = Date.now();
users[id] = name; //키밸류형식으로 등록하였다.
res.writeHead(201);
res.end('등록 성공');
});
}
} else if (req.method === 'PUT') {
if (req.url.startsWith('/user/')) {
//start가 user/라고 되어있으니 user/1 도 속한다.
//req.url.startsWith -> 문자열.startsWith
const key = req.url.split('/')[2];
//문자열 기능중에 split기능이 있다. 구분인자는 `/`, [2]는 인덱스 호출번호.
// ` /user/1`을 split하면 ' ', 'user', '1' 3가지 인자가 배열에 들어간다.
//이러한 것들을 key값에 넣어주겠다라는 뜻이다. timestamp로 들어간다.
let body = '';
req.on('data', (data) => {
body += data;
});
return req.on('end', () => {
console.log('PUT 본문(Body):', body); //우측 body에 데이터가 다 담겼다.
users[key] = JSON.parse(body).name;
//위에서 timestamp로 받은 값에 대한 users배열을 수정하게 되겠다.
return res.end(JSON.stringify(users));
});
}
} else if (req.method === 'DELETE') {
if (req.url.startsWith('/user/')) {
const key = req.url.split('/')[2];
delete users[key]; //object안의 원하는 item을 삭제하고 싶다면!!
return res.end(JSON.stringify(users));
}
}
res.writeHead(404);
return res.end('NOT FOUND');
} catch (err) {
console.error(err);
res.writeHead(500);
res.end(err);
}
})
.listen(8082, () => {
console.log('8082번 포트에서 서버 대기 중입니다');
});
const http = require('http')
const fs = require('fs').promises
const users = {} // 데이터 저장용
const server = http.createServer(async(req,res) => {
try {
if (req.method === 'GET') { //GET메소드로 들어 왔다면!
if(req.url === '/'){ //url이 기본 url로 들어 왔다면! 첫 화면을 뜻함
const data = await fs.readFile('./restFront.html') //그러면 해당 html읽어서 보여줄께!
res.writeHead(200, {'Content-Type': 'text/html; charset=utf-8'})// writeHead가 없다면 위 html파일이 평문으로 들어간다!
return res.end(data)
} else if (req.url === '/about') {
const data = await fs. readFile('./about.html') //about 버튼을 눌러보자
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' })
return res.end(data)
} else if (req.url === '/users') {
res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' })
return res.end(JSON.stringify(users)) //JSON으로 바꿔서 보내준다
}
try { // ./restFront.css, restFront.js파일을 불러오면
const data = await fs.readFile(`./${req.url}`) //메서드가 GET이면 다시 req.url로 요청 주소를 구분한다! //.then의파라미터에 해당하는 것이 await...이다. data가 곧 .then의 파라미터
return res.end(data)
} catch(err) {
console.error(err)
}
} else if (req.method === 'POST') {
if(req.url === '/user') {
let body = '' //빈문자열을 만든다. string으로 받으려 한다. 무엇을?
req.on('data',(data) => {
body = body + data
})
return req.on('end',()=> {
console.log('POST 본문 (body) : ', body)
const {name} = JSON.parse(body) //body에 담긴 부분이 JSON이고 parse(파싱)을 해줘서 object로 만들어서 넣는다. 객체화 한다.
//JSON은 객체는 아니지만 형태는 객체처럼 문자열로 온다.
const id = Date.now() //현제시간 timestamp 형태로 찍힌다.
users[id] = name//프론트에서 name값을 받아서 백엔드로 준다. 그걸 가지고 users객체에 담을 것이다. 그때 키가 필요하고, 키는 현재시간과
//처음 user={}빈객체이고 위의 id가 123으로 들어왔고, name이 김예찬으로 들어왔따면 {123:김예찬}이렇게 저장된다.
//users[id] id는 ''스트링 형식으로 들어간다.
console.log(users)
res.writeHead(201,{ 'Content-Type': 'text/plain; charset=utf-8' })
res.end('ok')
})
}
} else if (req.method === 'PUT') {
if (req.url.startsWith('/user/')) { // /user/1333.adsdf 이렇게 하면 다된다. /user/로 시작만 하면
// 주소 : 3000/user/123124123 이런식으로 요청이 들어온다. 그래서 split으로 처리한다.
console.log(req.url) //rul이 어떻게 들어오는지 알 수 있다.
const key = req.url.split('/')[2] //'/' 기준으로 잘라준다. /user/123 => ['','user','123'] 문자열을 배열화 한다.
console.log(key)
let body =''
req.on('data', (data) =>{ //data가 chunk로 온다?!
body +=data
})
return req.on('end', ()=> {
console.log('PUT 본문 : ',body)
users[key] = JSON.parse(body).name
res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8'})
res.end('ok')
// return res.end(JSON.stringify(users));
})
}
} else if (req.method === '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'})
res.end('ok')
}
}
} catch (err) { //err은 변수 이름으로 error해도 된다.
console.error(err)
res.writeHead(500,{'Content-Type': 'text/plain; charset=utf-8'})
res.end(err.message)
}
})
server.listen(3000)
server.on('listening', () => {
console.log('포트 3000번 사용중')
})
server.on('error', (err) => { //err은 변수 이름으로 error해도 된다.
console.error(err)
})
일반적으로 Head에 담아보낸다.
const http = require('http');
http.createServer((req, res) => {
console.log(req.url, req.headers.cookie);
res.writeHead(200, { 'Set-Cookie': 'mycookie=test' }); //여기에 쿠키 있음.
res.end('Hello Cookie');
})
.listen(8083, () => {
console.log('8083번 포트에서 서버 대기 중입니다!');
});