2021-12-14 BE
블로그 내 코드 자료 출처
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를 사용한 예외처리
예외처리를 위해 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://media.vlpt.us/images/ansunny1170/post/2e01ffdf-845c-4105-932e-68dbfd99a919/image.png)
}
})
},1000)
내부모듈 + promises를 사용한 예외처리
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);
자주발생하는 error들 p.165
공부
http 모듈로 서버 만들기
요청과 응답 이해하기
http.createServer(res,res)
요청과 응답 이해하기
http.createServer(res,res)
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주소 확인 가능하다.
http.createServer 실습
이벤트 리스너 방식
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파일을 읽어서 createServer()하기 async-await
<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번으로 실행하고 있음')
})
html파일을 읽어서 createServer()하기 .then
//.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번으로 실행하고 있음')
})
REST란?
Representational State Transfer 의 약자
- 요청 메소드 : GET, POST, PUT, PATCH, DELETE, OPTIONS
- GET : 서버 자원을 가져오고자 할 때 사용. 요청의 본문에 데이터를 넣지 않는다. 데이터를 서버로 보내야 한다면 쿼리스트링을 사용한다.
- POST : 서버에 자원을 새로 등록하고자 할 때 사용. 요청의 본문에 새로 등록할 데이터를 넣어 보낸다.
- PUT : 서버의 자원을 요청에 들어 있는 자원으로 치환하고자 할 때 사용. 요청의 본문에 치환할 데이터를 넣어 보낸다.(전체다 변경해야 해서 불편할 때가 있다.)
- PATCH : 서버 자원의 일부만 수정하고자 할 때 사용. 요청의 본문에 일부 수정할 데이터를 넣어 보낸다.
- DELETE : 서버의 자원을 삭제하고자 할 때 사용. 요청의 본문에 데이터를 넣지 않는다.
- OPTIONS : 요청을 하기 전에 통신 옵션을 설명하기 위해 사용. 12장에 자주 나온다.
restServer.js 핵심 코드
코드로 보면
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번 포트에서 서버 대기 중입니다');
});
- 클라이언트 HTTP 요청
※ 중요! 핵심코드 실습 주석 확인 필요
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)
})
쿠키와 세션
쿠키 설정해 보기 자습 p.190
- 로그인 할 때 사용, 세션유지
로그인 하면, 로그인 성공했어라고 하고 서버에서 쿠키하나 줄께.... 하는듯이 ㅋㅋ
로그인한 상태를 유지시켜준다. 그리고 만료시간도 있다.
로그인 하면, 로그인 성공했어라고 하고 서버에서 쿠키하나 줄께.... 하는듯이 ㅋㅋ
로그인한 상태를 유지시켜준다. 그리고 만료시간도 있다.
일반적으로 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번 포트에서 서버 대기 중입니다!');
});
Author And Source
이 문제에 관하여(2021-12-14 BE), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@ansunny1170/2021-12-14-BE저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)