-
NodeJS #4 axios, cookie학원/NodeJS 2022. 4. 21. 15:43
axios를 이용한 간단한 페이지 만들기
-> input으로 입력 받은 값을 순서대로 출력하기
**서버 쪽 내용(05_Server05.js)을 바꿨다면 서버를 껐다 켜줄 것
05_Front.html
<!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>Node.js Web Server</title> <style type="text/css"> a{color:blue; text-decoration: none;} </style> </head> <body> <nav> <a href="/"> HOME </a> <a href="/about"> ABOUT </a> </nav> <div style="margin-top: 30px;"> <form id="form"> <input type="text" id="username"> <button type="submit"> 등록 </button> </form> </div> <div id="list"> </div> <script src="https://unpkg.com/axios/dist/axios.min.js"></script> <script type="text/javascript"> getUsers() document.getElementById('form').addEventListener('submit', async(e)=>{ //e에는 이벤트의 주체(form)가 전달됨 e.preventDefault(); const name = e.target.username.value console.log(name) if(!name) { return alert('이름을 입력하세요') } try{ console.log('try') await axios.post('/user', {name}) console.log('await') getUsers() } catch(err) { console.log('에러') } e.target.username.value = '' console.log('function end') //input id="username" 을 빈칸으로 초기화 //target = form id="form" }) async function getUsers(){ try{ 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값 마다 익명함수 실행 const userDiv = document.createElement('div') const span = document.createElement('span') span.textContent = users[key] //span안에 users의 key값 삽입 //수정버튼 생성 const edit = document.createElement('button') edit.textContent = '수정' edit.addEventListener('click', async () => { const name = prompt('바꿀 이름을 입력하세요') if(!name){ return alert('이름을 입력해주세요') } try { await axios.put('/user/' + key, {name}) //url = /user/바뀐이름 getUsers() } catch(err) { console.error(err) } }) //삭제 버튼 생성 const remove = document.createElement('button') remove.textContent = '삭제' remove.addEventListener('click', async () => { try { let result = confirm('삭제할까요?') if(result){ await axios.delete('/user/' + key) //url = /user/바뀐이름 getUsers() } } catch(err) { console.error(err) } }) userDiv.appendChild(span) //div안에 span 삽입 userDiv.appendChild(edit) //div안에 수정버튼 삽입 userDiv.appendChild(remove) //div안에 삭제버튼 삽입 list.appendChild(userDiv) //div를 list에 삽입 }) } catch(err) { console.error(error) } } </script> </body> </html>
05_Server05.js
const http = require('http') const fs = require('fs').promises let users = {} //서버가 종료될 때까지 값이 유지되는 변수 http.createServer( async (req, res)=>{ try { if(req.method == 'GET') { if(req.url === '/') { //첫번째 페이지로 갈 때 const data = await fs.readFile('./05_Front.html') res.writeHead(200, {'Content-Type' : 'text/html; charset=utf-8'}) return res.end(data) //파일 내용 전송 후 async(req, res)=>{} 함수가 //종료되도록 return //return이 없으면 try문 아래에 400 NOTFOUND도 같이 실행되게 됨 } 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'){ return res.end(JSON.stringify(users)) //user 객체 안의 내용을 json 형식으로 변경하여 전송 } } else if (req.method == 'POST'){ if(req.url === '/user') { //req에 전송된 자료를 stream 형식으로 받아 body변수에 대입 let body = '' req.on('data', (data)=>{ body += data }) //req.on() : request의 동작을 첫 번째 인수로 전달된 키워드로 구분, 익명함수를 실행한다. //전달된 자료를 모두 객체 형식으로 받아서 처리한다. return req.on('end', ()=> { const {name} = JSON.parse(body) //전달된 데이터를 name 변수에 저장 const id = Date.now() //id 변수에 날짜를 추출 users[id] = name; res.writeHead(201, {'Content-Type' : 'text/plain; charset=utf-8'}) res.end('ok') //함수에서 빠져 나감 }) } } else if (req.method == 'PUT') { if(req.url.startsWith('/user/')){ // axios.put('/user/' + key, {name}) 이 전달되기 때문에 // '/user/'로 시작하는 주소를 찾도록 함 const key = req.url.split('/')[2] // req.url.split('/')[0]: , [1]: user, [2]: key console.log(key) // 1650515427987 (POST ('/user')에서 설정한 Date.now()의 값) let body = '' req.on('data', (data)=> { body+= data }) return req.on('end', ()=>{ users[key] = JSON.parse(body).name res.writeHead(201, {'Content-Type' : 'text/plain; charset=utf-8'}) res.end('ok') }) } } else if (req.method == 'DELETE'){ if(req.url.startsWith('/user/')){ const key = req.url.split('/')[2] delete users[key] res.writeHead(201, {'Content-Type' : 'text/plain; charset=utf-8'}) return res.end('ok') } } //위 if-else 문 어디에도 걸리지 않을 경우 //아래 코드를 실행 res.writeHead(404) return res.end('NOT FOUND') } catch(err) { //서버 실행상의 에러를 처리 // : 404 에러 등은 여기서 처리 안됨 console.error(error) res.writeHead(500, {'Content-Type' : 'text/html; charset=utf-8'}) return res.end(err.message) } }).listen(8090, ()=>{ console.log('Server is ready in port 8090') })
결과
Cookie Server
쿠키 Cookie
requesst의 단점 : 누가(어떤 client가) 보낸 요청인지 알수 없다. (ip주소와 브라우저 정보 정도만 알 수 있음)
-> 쿠키로 이 단점을 해결가능
쿠키는 키:값의 쌍으로 이루어진 데이터로 매 요청(request)마다 서버에 쿠키가 동봉되어 보내진다
-> 이 쿠키를 읽어 어떤 client로 부터의 요청인지 파악이 가능함
http 요청과 응답은 헤더와 본문을 가지는데 헤더는 요청/응답의 내용을 담고 있고 본문은 주고 받는 실제 데이터를 가지고 있다.
-> 쿠키는 부가적인 정보이므로 헤더에 저장하는 것
쿠키를 직접 넣어 구현하려면 writeHead 메서드를 이용해 요청 헤더에 입력한다
쿠키의 내용은 Set-Cookie로 브라우저에 쿠키를 설정하라고 명령을 내린다
const http = require('http') http.createServer((req, res) => { console.log(req.url, req.headers.cookie) //클라이언트 요청에는 header의 쿠키가 자동으로 동봉됨 res.writeHead(200, { 'Set-Cookie' : 'mycookie=test' }) res.end('<h1>Hello Cookie</h1>') }).listen(8090, () => { console.log('Server is ready in port 8090') })
쿠키 이용하기
07_CookieServer02.js
const http = require('http') const fs = require('fs').promises const url = require('url') const qs = require('querystring') const parseCookies = (cookie='') => cookie .split(';') .map(v=>v.split('=')) //cookie1=test1; cookie2=test2; 형태로 전달되는 쿠키를 //쿠키 단위로 나누고 다시 '='로 분리 .reduce(( acc, [k, v]) =>{ acc[k.trim()] = decodeURIComponent(v) return acc }, {}) // 분리된 cookie1, test를 각각 k와 v에 전달 -> 객체 형태로 만든 후 acc에 저장 --> 마지막 {} 는 분리된 쿠키들이 [k, v] 형태가 되어 객체로 저장 취합된다는 의미 http.createServer(async (req, res) => { const cookies = parseCookies ( req.headers.cookie ) // key:value 형태로 변환후 cookies 변수에 저장 if(req.url.startsWith('/login')) { //쿼리 스트링 분리 const {query} = url.parse(req.url) console.log(query) //name=%EA%B9%80%EC%A0%9C%EB%8F%99 const {name} = qs.parse(query) const expires = new Date() //쿠키 유효시간 설정을 위해 현재 날짜 데이터 생성 expires.setMinutes(expires.getMinutes()+1) //쿠키 유효시간을 현재 시간 +1분으로 설정 res.writeHead(302, { Location : '/', 'Set-Cookie': `name=${encodeURIComponent(name)}; Expires=${expires.toGMTString()}; HttpOnly; Path=/` }) //경로및위치, 유효시간, 쿠키 접근을 http 방식으로만 제한 res.end() } else if(cookies.name) { //로그인 되어 세션값이 존재하는 경우 res.writeHead(200, {'Content-Type' : 'text/plain; charset=utf-8'}) res.end(`${cookies.name}님 안녕하세요`) }else { try { const data = await fs.readFile('./06_Cookie_page.html') res.end(data) } catch(err) { res.writeHead(500, {'Content-Type' : 'text/plain; charset=utf-8'}) res.end(err.message) } } } ).listen(8090, () => { console.log('Server is ready in port 8090') })
06_Cookie_page.html
<!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>Document</title> </head> <body> <form action="/login"> <input id="name" name="name" placeholder="please enter your name"> <button id="login">login</button> </form> </body> </html>
검사 창에서 쿠키의 정보 확인 가능 -> 쿠키의 유효시간을 1분으로 설정했기 때문에 '~님 안녕하세요' 화면에서 1분 후 새로 고침하면 처음 로그인 창으로 돌아간다
session에 cookie 값을 저장한 후 이용하기
const http = require('http') const fs = require('fs').promises const url = require('url') const qs = require('querystring') const parseCookies = (cookie='') => cookie .split(';') .map(v=>v.split('=')) .reduce(( acc, [k, v]) =>{ acc[k.trim()] = decodeURIComponent(v) return acc }, {}) const session = {} http.createServer(async(req, res) => { const cookies = parseCookies(req.headers.cookie) if(req.url.startsWith('/login')) { const {query} = url.parse(req.url) const {name} = qs.parse(query) console.log('name : ' + name) //세션, 쿠키 수명 계산 const expires = new Date() expires.setMinutes(expires.getMinutes() + 1) //세션 객체에 저장하기 위한 고유 키값 const uniqueInt = Date.now() //Cookies -> name = ${uniqueInt} //Session -> ${uniqueInt} : '홍길동' //의 형태로 저장됨 //세션의 값들은 서버에서 관리 : 세션에서 해당값의 유무, 쿠키 값의 유무를 검사해 조회한다 session[uniqueInt] = { name, expires, } res.writeHead(302, { Location: '/', 'Set-Cookie' : `session=${uniqueInt}; Expires=${expires.toGMTString()}; HttpOnly; Path=/` }) //쿠키에는 고유 키 값(uniqueInt)을 value로써 session key에 저장 (실제 값은 없음) res.end() } else if(cookies.session && session[cookies.session].expires > new Date() ) { //쿠키에 session이라는 key가 존재 && session의 유효시간이 지나지 않있을 때 console.log(cookies.session) res.writeHead(200, {'Content-Type' : 'text/plain; charset=utf-8'}) res.end(`${session[cookies.session].name}님 안녕하세요`) } else { try { const data = await fs.readFile('./06_Cookie_page.html') res.end(data) } catch(err) { res.writeHead(500, {'Content-Type' : 'text/plain; charset=utf-8'}) res.end(err.message) } } }).listen(8090, () => { console.log('Server is ready in port 8090') })
결과는 위에 cookie 이용하기 항목과 같으나
cookie에는 고유 키값만 저장하고 session에 실제 data를 저장해 불러온다는 방식이 다르다.
'학원 > NodeJS' 카테고리의 다른 글
NodeJS#5 라우터 분리하기, secret, nunjucks (0) 2022.04.25 NodeJS #4 Express Server, 파일 업로드 (0) 2022.04.22 NodeJS#3 Internal Module, await, (0) 2022.04.20 node js #2 : 객체, 배열, Internal Module(cosole, timer) (0) 2022.04.19 node js, express server (0) 2022.04.18