-
Node.js(5) - 미들웨어와 라우팅 사용하기웹 개발/node.js 2023. 4. 18. 22:14
미들웨어 간 데이터 교환하기
- 물론 req.session 객체에 데이터를 넣어도 되지만, 세션이 유지되는 동안에 데이터도 계속 유지된다는 단점이 있음
- 우리는 요청이 끝날 때까지만 데이터를 유지하고 싶기 때문에 res.locals 객체에 데이터를 넣어 두어야 한다.
- 새로운 요청이 오면 res.locals는 초기화된다.
app.use((req, res, next) => { res.locals.data = '데이터 넣기'; next(); }, (req, res, next) => { console.log(res.locals.data); // 데이터 받기 next(); });
미들웨어 안에 미들웨어 넣기
- 기존의 미들웨어 기능 확장에 용이하다.
app.use(morgan('dev')); // 또는 app.use((req, res, next) => { morgan('dev')(req, res, next); });
app.use((req, res, next) => { if (process.env.NODE_ENV === 'production') { morgan('combined')(req, res, next); } else { morgan('dev')(req, res, next); } });
multer
- 이미지, 동영상 등을 비롯한 여러 가지 파일을 멀티파트 형식( enctype이 multipart/form-data인 폼을 통해 업로드하는 데이터의 형식)으로 업로드할 때 사용하는 미들웨어이다.
multipart.html
<form action="/upload" method="post" enctype="multipart/form-data"> <input type="file" name="image"/> <input type="text" name="title"/> <button type="submit">업로드</button> </form>
app.js에 추가해주기
const multer = require('multer'); const upload = multer({ storage: multer.diskStorage({ //storage 속성 : 어디에(destination) 어떤 이름으로(filename) 저장할지를 넣기 // destination과 filename 함수의 req 매개변수에는 요청에 대한 정보가, file 객체에는 업로드한 파일에 대한 정보가 있음 destination(req, file, done) { done(null, 'uploads/'); //done : 함수임. 첫 번째 인수에는 에러가 있다면 에러를 넣고, 두 번째 인수에는 실제 경로나 파일 이름을 넣어주면 된다. (/uploads) // req나 file의 데이터를 가공해서 done으로 넘기는 형식이다. }, filename(req, file, done) { const ext = path.extname(file.originalname); // uploads라는 폴더에 [파일명+현재시간.확장자] 파일명으로 업로드함 done(null, path.basename(file.originalname, ext) + Date.now() + ext); }, }), limits: { fileSize: 5 * 1024 * 1024 }, //limits 속성에는 업로드에 대한 제한 사항을 설정할 수 있으며, 파일 사이즈(fileSize, 바이트 단위)는 5MB로 제한해둠 });
- 그런데 여기서 멀티 파일을 저장할 uploads 폴더가 필요하기 때문에, 직접 만들어주거나 fs모듈을 사용하여 서버가 시작할 때 생성해준다.
app.js에 추가해주기
const fs = require('fs'); try { fs.readdirSync('uploads'); } catch (error) { console.error('uploads 폴더가 없어 uploads 폴더를 생성합니다.'); fs.mkdirSync('uploads'); }
파일을 하나만 업로드할 수 있도록 하는 경우에는 single 미들웨어를 사용한다.
app.js에 추가하기
app.post('/upload', upload.single('image'), (req, res) => { console.log(req.file, req.body); res.send('ok'); });
- single 미들웨어를 라우터 미들웨어 앞에 넣어두면, multer 설정에 따라 파일 업로드 후 req.file 객체가 생성된다.
인수는 input 태그의 name이나 폼 데이터의 키와 일치하게 넣으면 된다.
- 업로드 성공 시 결과는 req.file 객체 안에 들어 있으며, req.body에는 파일이 아닌 데이터인 title이 들어 있게 된다.
req.file 객체 생김새
{ fieldname: 'img', originalname: 'nodejs.png', encoding: '7bit', mimetype: 'image/png', destination: 'uploads/', filename: 'nodejs1514197844339.png', path: 'uploads\nodejs1514197844339.png', size: 53357 }
여러 파일을 업로드하는 경우
multipart.html
<form id = "form" action="/upload" method="post" enctype="multipart/form-data"> <input type="file" name="many" multiple /> <input type="text" name="title" /> <button type="submit">업로드</button> </form>
미들웨어는 single 형식 대신 array로 교체하여 사용해야 한다.
app.js
app.post('/upload', upload.array('many'), (req, res) => { console.log(req.files, req.body); res.send('ok'); }); //싱글 형식일 때 //app.post('/upload', upload.single('image'), (req, res) => { // console.log(req.file, req.body); // res.send('ok'); //});
- 업로드 결과는 req.files 배열에 들어있게 됨
파일을 여러 개 업로드하지만 input 태그나 폼 데이터의 키가 다른 경우 = fields 미들웨어 사용하기
multipart.html
<form id = "form" action="/upload" method = "post"> <input type = "file" name = "image1"/> <input type = "file" name = "image2" /> <input type = "text" name = "title" /> <button type="submit">업로드</button> </form>
app.js
fields 미들웨어의 인수로 input 태그의 name을 각각 적습니다. app.post('/upload', upload.fields([{ name: 'image1' }, { name: 'image2' }]), (req, res) => { console.log(req.files, req.body); res.send('ok'); }, );
- 업로드 결과는 req.files.image1, req.files.image2에 각각 들어 있게 된다.
파일을 업로드하지 않고도 멀티파트 형식으로 업로드하는 경우
multipart.html
<form id= "form" action="/upload" method = "post" enctype = "multipart/form-data"> <input type = "text" name = "title" /> <button type = "submit">업로드</button> </form>
app.js
app.post('/upload', upload.none(), (req, res) => { console.log(req.body); res.send('ok'); });
- 파일을 업로드하지 않았기 때문에 req.body만 존재한다.
파일 업로드 관련 미들웨어 관계도
Router 객체로 라우팅 분리하기
- app.js에서 app.get 같은 메서드가 라우터 부분이고, 이 부분을 routes 폴더에 분리해서 만들어주기
routes/index.js
const express = require('express'); const router = express.Router(); // GET / 라우터 router.get('/', (req, res) => { res.send('Hello, Express'); }); module.exports = router;
routes/user.js
const express = require('express'); const router = express.Router(); // GET /user 라우터 router.get('/', (req, res) => { res.send('Hello, User'); }); module.exports = router;
app.js
const express= require('express'); const morgan = require('morgan'); const cookieParser = require('cookie-parser'); const session = require('express-session'); const dotenv = require('dotenv'); const path = require('path'); const multer = require('multer'); const fs = require('fs'); const app = express(); dotenv.config(); //라우터 불러오기 const indexFouter = require('./routes'); // index.js는 생략할 수 있기 때문에 index.js를 불러옴 const userRouter = require('./routes/user'); app.set('port', process.env.PORT || 3000); app.use(morgan('dev')); app.use('/', express.static(path.join(__dirname, 'public'))); app.use(express.json()); app.use(express.urlencoded({extended:true})); app.use(cookieParser(process.env.COOKIE_SECRET)); app.use(session({ resave : false, saveUninitialized:false, secret : process.env.COOKIE_SECRET, cookie:{ httpOnly : true, secure : false, }, name : 'session-cookie', })); app.use('/', indexRouter); // indexRouter는 app.use('/')에 연결, use의 '/'와 get의 '/'가 합쳐져 GET / 라우터가 된다. app.use('/user', userRouter); // userRouter는 app.use('/user')에 연결, userRouter는 use의 '/user'와 get의 '/'가 합쳐져 GET /user 라우터가 됨 // app.use로 연결할 때 주소가 합쳐진다. app.use((req, res, next) => { res.status(404).send('Not Found'); }); app.use((err, req, res,next) => { console.error(err); res.status(500).send(err.message); }
next('route')
- 라우터에 연결된 나머지 미들웨어들을 건너띌 수 있도록 함
routes/index.js
const express = require('express'); const router = express.Router(); router.get('/', (req, res, next) => { next('route'); //두 번째, 세 번째 미들웨어는 실행되지 않고, 주소와 일치하는 다음 라우터로 넘어가게 된다. }, (req, res, next) => { console.log('실행되지 않습니다'); next(); }, (req, res, next) => { console.log('실행되지 않습니다'); next(); }); router.get('/', (req, res) => { console.log('실행됩니다'); res.send('Hello, Express'); }); module.exports = router;
- 같은 주소의 라우터를 여러 개 만든 것(index.js에 대해서)
- 라우터가 몇 개이든 상관없이 next를 호출하면 다음 미들웨어가 실행된다.
라우트 매개변수
router.get('/user/:id', (req, res) => { console.log(req.params, req.query); });
: id
- /users/1이나 /users/123 등의 요청을 처리하도록 해준다.
- :id에 해당하는 1이나 123을 조회할 수 있다는 점이며, req.params 객체 안에 들어 있다.
- :id이면 req.params.id로, :type이면 req.params.type으로 조회할 수 있음
- 일반 라우터 뒤에 있어야 다른 라우터를 방해하지 않는다.
router.get('/user/:id', (req, res) => { console.log('얘만 실행됩니다.'); }); router.get('/user/like', (req, res) => { console.log('전혀 실행되지 않습니다.'); });
- /user/like와 같은 라우터는 /user/:id 같은 라우트 매개변수를 쓰는 라우터보다 위에 위치해야 한다.
올바른 표현 방식
router.get('/user/like', (req, res) => { console.log('이제 실행됩니다.'); }); router.get('/user/:id', (req, res) => { console.log('얘도 실행됩니다.'); });
주소에 쿼리스트링 사용하기
- 쿼리스트링의 키-값 정보는 req.query 객체 안에 들어 있다.
주소가 같지만 메서드가 다른 코드에 대한 처리
req.params
{ id: '123'}
req.query
{ limit: '5', skip: '10' }
routes/abc.js
router.route('/abc') .get((req, res) => { res.send('GET /abc'); }) .post((req, res) => { res.send('POST /abc'); });
req 객체 메서드 및 속성
res 객체의 속성 및 메서드
메서드 체이닝
- res, req 객체의 메서드를 연달아 이어붙여 코드양을 줄이도록 함
res .status(201) .cookie('test', 'test') .redirect('/admin');
'웹 개발 > node.js' 카테고리의 다른 글
Node.js(7) - 데이터베이스, 시퀄라이즈, 몽구스 (0) 2023.04.22 Node.js(6) - 템플릿 엔진 (0) 2023.04.21 node.js(4) - Express.js 시작하기 (0) 2023.04.15 Node.js(3) (0) 2023.04.14 Node.js(2) (0) 2023.04.12