📝

13. routing_and_middleware

 

1. express router

  • app1을 참고하여 about, product, contact의 페이지를 직접 만들어보세요.
// 파일이름 : 009_routing_and_middleware\app1.js // 라우팅 : URL보고 어디로 가! 지시해주는 것. // 미들웨어 : 요청과 응답 중간(middle)에서 무언가를 해주는 것. // 사용자 작성 미들웨어, 내부 미들웨어, 외부 미들웨어 // npm init --yes // npm i express // npm i nodemon --save-dev // -> nodemon app1 으로 실행 가능 // 기본 라우팅 공식문서 // https://expressjs.com/ko/starter/basic-routing.html // 라우팅 공식문서 // https://expressjs.com/ko/guide/routing.html // 정규표현식 -> 노션 문서 참고 // https://ridibooks.com/books/2773000049 const express = require('express'); const indexRouter = require('./router'); // 뒤에 index.js 생략 가능 const aRouter = require('./router/a.js'); const bRouter = require('./router/b.js'); const cRouter = require('./router/c.js'); const app = express(); // 최종 실행 코드(마지막 실습) // 아래처럼 여러개의 미들웨어를 하나의 use에 매핑 가능 // 순서가 중요함, 모든 url 매핑 확인 전! 무조건 실행되는 코드. // app.use((req, res, next) => { //     console.log('one'); //     next(); // }, (req, res, next) => { //     console.log('two'); //     next(); // }, (req, res, next) => { //     console.log('three'); //     next(); // }) app.use('/', indexRouter); app.use('/a', aRouter); app.use('/b', bRouter); app.use('/c', cRouter); app.use((req, res, next) => {     res.status(404).send('못찾음!'); // res.send는 res.status(200).send('')     // 보안상 status는 좀 더 고민해본 후 작성, 200을 일부러 보내주는 경우가 많습니다. }); app.use((err, req, res, next) => {     console.log('애러발생!');     console.log(err); });  // 매개변수가 4개인것만 애러처리합니다. 주의해주세요. app.listen(8080); // 보통 위에 있고 맨 마지막에는 error 처리하는 경우가 많음
// router 폴더에 index.js const express = require('express'); const router = express.Router(); router.get('/', (req, res, next) => { res.send('hello index!') }) module.exports = router;
// router 폴더에 a.js, b.js, c.js const express = require('express'); const router = express.Router(); router.get('/', (req, res, next) => { res.send('hello a!') // 여기만 수정하시면 됩니다. }) module.exports = router;

2. fs, path

// 파일이름 : 009_routing_and_middleware\app2.js // npm init --yes // npm i express // npm i nodemon --save-dev // -> nodemon app1 으로 실행 가능 const express = require('express'); const indexRouter = require('./router'); // 뒤에 index.js 생략 가능 const blogRouter = require('./router/blog.js'); const app = express(); app.use('/', indexRouter); app.use('/blog', blogRouter); app.use((req, res, next) => {     res.status(404).send('Not Found'); }); app.use((err, req, res, next) => {     console.log('애러발생!');     console.log(err); }); app.listen(8080);
// router 폴더에 blog.js 파일 const express = require('express'); const fs = require('fs'); const path = require('path'); const router = express.Router(); router.get('/', (req, res, next) => { res.end(fs.readFileSync(path.join(__dirname, '../resource/blog.html'))); }) // 여기서 blog/1 이런식에 url을 처리하면 됩니다. router.get('/:id', (req, res, next) => { res.send(req.params.id + 'page!!'); }) module.exports = router;
// rersource 폴더에 blog.html // style은 안됩니다! 다른 파일에서 파일을 또 읽어오는 것이 안된다는 얘기에요. <!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> <link rel="stylesheet" href="test.css"> </head> <body> <h1>hello world</h1> </body> </html>
h1 { color:red; }

3. dotenv

// 파일이름 : 009_routing_and_middleware\app3.js // npm i morgan dotenv const express = require('express'); const morgan = require('morgan'); // 추가로그 확인 const dotenv = require('dotenv'); // 미들웨어 아닙니다. const path = require('path'); dotenv.config(); // process.env 관리를 위해 사용합니다. console.log("DB_HOST:", process.env.SECRET); console.log("DB_HOST:", process.env.DB_HOST); console.log("DB_USER:", process.env.DB_USER); console.log("DB_PASSWORD:", process.env.DB_PASSWORD); const app = express(); app.use(morgan('dev')); // 배포할 때에는 dev 대신 combined, combined를 사용하면 브라우저, ip 등이 뜹니다. app.use('/', express.static(path.join(__dirname, 'resource'))); // 해당 폴더에서 정적파일 제공(기본 제공), resouce는 외부노출 url이 아닙니다. // 보통은 public 폴더로 사용하는데 보안상 권장하지 않음 // static 옵션은 공식 문서 참고 // 링크 : http://expressjs.com/ko/api.html#express.static app.use(express.json()) // body parsing // 그 외에도 common, short, tiny 등 사용 가능 app.use(express.urlencoded({ extended: false })); // 위와 동일하게 body parsing // 주로 html의 form 데이터 파싱(이미지는 처리 못해요. multer사용을 권합니다.), 옵션은 필수입니다. 최근에 express에 일부 기능이 들어와 있는 상태입니다. 따로 npm i body-parser를 안해주셔도 됩니다. // extended true -> qs 모듈이 query 해석 // extended false -> node의 querystring 모듈이 qeury 해석 // post와 put에서 주로 사용. req.on('data'), req.on('end')를 사용할 필요가 없음 app.get('/', (req, res, next) => {     res.status(200).send('hello world'); }) app.use((req, res, next) => {     // 위에 요청 처리 구문이 없으면 모든 요청에 대한 처리     // 위에 요청이 있다면 없는 요청에 대한 처리     // 이 코드가 맨 앞으로 가면 모든 요청에 대해 404     res.status(404).send('Not Found'); }); app.use((err, req, res, next) => {     console.log('애러발생!');     console.log(err); }); app.listen(8080);
 

4. cors

// 파일이름 : 009_routing_and_middleware\app4.js // npm i cors // test.html은 liveserver로 실행시키세요. const express = require('express'); const cors = require('cors') const app = express(); app.use(cors()); //client와 server에 ip가 다른 경우 데이터 요청할 때 CORS 애러 발생! response headers에 Access-Control-Allow-Origin 이 없으면 CORS 애러 발생합니다. 브라우저에서 주는 애러에요. 보안성을 위해 전체 공개가 아니라 옵션값을 이용해서 ip를 지정하는 것을 권해드립니다. // app.use(cors( //     origin: [88.88.88.88:3000] // 요청 url과 port // )) app.get('/', (req, res, next) => {     // res.send('hello world');     res.json({"이름":"신발", "가격":100000}); }) app.listen(8080);
<!-- 파일이름 : 009_routing_and_middleware\test.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> <h1 id="title">이름</h1> <p id="cost">가격</p> <script> const title = document.getElementById('title'); const cost = document.getElementById('cost'); fetch('http://localhost:8080', {method: 'GET'}) // .then(console.log) //주석 풀면 콘솔에서 응답값 볼 수 있음 .then(res => res.json()) .then(json => { title.innerHTML = json.이름; cost.innerHTML = json.가격; }) .catch(console.log); </script> </body> </html>
 

5. cookie-parser

  • 쿠키와 세션 google 검색.
  • 쿠키파서는 요청에 있는 쿠키를 파싱하여 request.cookies 객체로 만듭니다.
// 파일이름 : 009_routing_and_middleware\app5.js // npm i cookie-parser express-session // 쿠키나 url에서 한글 사용하면 애러가 날 수도 있어서 encodeURIComponent() 해주시는 것이 좋습니다. const express = require('express'); // 쿠키는 유효기간이 있는 키와 값의 쌍이라고 보시면 됩니다. 로그인 구현에서 많이 사용되지만 // 로그인에서만 사용되는 것은 아니에요. 사용자 정보를 저장하기 위해서도 사용됩니다. // 보통은 브라우저를 종료할 때 사라집니다. // 1. 클라이언트가 서버에게 요청 // 2. 서버가 response값을 쿠키와 함께 응답 // 3. 쿠키와 함께 다시 req(사용자 인증) // 4. 서버가 response const cookieParser = require('cookie-parser'); // 개발자도구 Network > Headers에 보안관련된 값들을 넣어줌 const app = express(); app.use(express.json()); app.use(cookieParser()); // 보통 안에 서명키, 보안상 취약하기 때문에 다른 파일로 빼놓음(process.env.SECRET), signedCookies로 값을 가져올 수 있음 app.get('/', (req, res, next) => { console.log(req.body); console.log(req.cookies); // app.use(cookieParser()); 이걸 해줘야만 보여짐, 위에서 언급한 것처럼 signedCookies로 값을 가져올 수 있음 res.writeHead(200, {'Set-Cookie' : 'name=hojun'}); // res.cookie() : 쿠키의 옵션을 설정 // https://expressjs.com/ko/api.html#res.cookie // 1. 2번 실행하면 터미널에서 name:'hojun'이 보임 // 2. 개발자도구 > 네트워크 > localhost에 Response Headers에서 쿠키 볼 수 있습니다. // 3. 애플리케이션 > 쿠키 > localhost:8080에서도 볼 수 있습니다. // 4. 아래와 같이도 실행할 수 있으나 애플리케이션 쿠키에서는 보이지 않습니다. // res.writeHead(200, {'Set-Cookie' : 'name=hojun', 'Set-Cookie-hello' : 'pw=1234'}); // 5. 애플리케이션 > 쿠키 > 값 삭제하면서 확인해보세요. if(req.cookies.name){ res.end(`${req.cookies.name}, hello!`); } else { res.end('hello!'); } }) app.listen(8080);
 

6. express-session

  • 세션을 관리하기 위한 미들웨어 입니다.
// 파일이름 : 009_routing_and_middleware\app6.js // npm i cookie-parser express-session // jwt vs session라고 검색해보세요. 저는 jwt를 주로 사용하는 편입니다. const express = require('express'); const session = require('express-session'); const app = express(); app.use(express.json()); // app.use(session()); // 요청하는 사람마다의 각각의 세션을 저장(개인 인벤토리, 장바구니) // 아래처럼 관리하면 큰일납니다. // 요청에서 req.session.name = 'hojun' // 요청에서 req.session.id = 'hojun' // 요청에서 req.session.pw = 'hojun123' // 브라우저는 key값 정도만, 중요한 정보는 서버에만 저장. // app.use(session({ // secret: process.env.COOKIE_SECRET, //.env에서 가져온 시크릿키, .env는 git ignore 꼭 해주세요. // resave: false, // 다시 요청이 오면 세션에 변동이 없어도 저장, 저장하지 않음. // saveUninitialized: false, // 세션에 내용 없어도 저장?, 놉! // cookie: { // httpOnly: true, // javascript로 조작하지 못하도록! 정보보안! 필수! // secure: false, // }, // name: 'session-cookie', // 난독화된 서명 문자열, 보통은 connect.sid // })); app.use(session({ secret: 'hello', resave: false, saveUninitialized: false, cookie: { httpOnly: true, // javascript로 조작하지 못하도록! 정보보안! 필수! secure: false, }, })); app.get('/', (req, res, next) => { console.log(req.body); console.log(req.session); // res.send('hello world'); if(!req.session.name){ req.session.name = 'hojun'; } else { req.session.name = 'hojun 재접속 -> 로그인 유지'; } res.send(`접속하는 개개인이 다릅니다 : ${req.session.name}`); // id 저장없이 로그인 사용자인지 판달할 수 있음. 이 test라는 값은 쿠키에서 가지고 있지 않음. }) app.listen(8080);
 

7. helmet

// 파일이름 : 009_routing_and_middleware\app7.js // npm i helmet const express = require('express'); const helmet = require('helmet');  const app = express(); // 개발자도구 > 네트워크 > localhost 외 아무것도 없음 app.use(helmet()); // localhost 외 보안에 정보에 필요한 다른 정보들이(Content-Security-Policy 등) 들어가 있는 것을 볼 수 있음 app.get('/', (req, res, next) => {     res.send('hello world'); }) app.listen(8080);