middleWare
: 들어오는 요청을 express.js에 의한 다양한 함수를 통해 자동으로 이동하는 것이다.
즉, 단일 요청 핸들러를 보유하는 대신, 응답을 전송하기 전까지 요청이 통과하게 될 다양한 함수들을 연결점을 제공한다.
~> 모든걸 단일의 함수를 사용하여 처리하기 보다는 코드를 다수의 블록 또는 조각으로 분할하여 처리한다.
따라서 미들웨어에는 다양한 기능을 제공할 제 3자(Third Party)패키지를 쉽게 express.js에 장착하여 특정 기능들을 추가한다.
const http = require("http");
const express = require("express");
const app = express();
app.use((req, res, next) => {
console.log("In the middleware");
next();
});
app.use((req, res, next) => {
console.log("In another middleware");
});
const server = http.createServer(app);
server.listen(3000);
실행을 해 보면 next()
로 인해 첫번째 미들웨어의 콘솔 로그와 두번째 미들웨어의 콘솔로그가 남는것이 확인 되어 진다.
만약 첫번째 미들웨어의 next()
를 제거하면 서버는 첫번째 미들웨어에 머무를 것이고 어떠한 응답객체를 전송하지 않았기 때문에 무한로딩 또는 무한 대기 상태에 빠지게 된다.
만약 미들웨어가 여러개인 경우, next()
를 활용해 다음 미들웨어로 전송하고 마지막 미들웨어에서는 응답 객체를 반환해줘야 할 것이다.
const http = require("http");
const express = require("express");
const app = express();
app.use((req, res, next) => {
console.log("In the middleware");
next();
});
app.use((req, res, next) => {
console.log("In another middleware");
res.header('Content-Type', 'text/html')
res.write("<html>");
res.write("<header><title>MiddleWare</title></header>");
res.write("<body>");
res.write('<h3>sendMethod Done</h3>')
res.write("</body>");
res.write("</html>");
res.end('<h2>res Done</h2>')
});
const server = http.createServer(app);
server.listen(3000);
app.use()
로 미들웨어를 추가하고 res.write()
를 통해 응답객체를 반환하였다.
res.write()을 통해 반환하는 방법도 있지만, res.send()
를 이용하여 응답객체를 반환할 수 있다.
res.write()
: 추가 패키지 없이, http만으로 가능한 전송함수이다. 또한 여러번 호출할 수 있고 단점으로는 head와 end함수를 직접 지정해야 한다.
res.send()
: express
라는 추가적인 패키지 설치가 필요하다.
send
는 http module에서 "end
와 동일한 기능"을 한다. write
는 여러번 사용할 수 있지만, send
는 "한번 만 사용"할 수 있다. 또한 자동으로 "head와 http 캐시를 지정"해 준다.
주의할 점은 send()
와 write()
를 혼용하여 사용 할 수 없다.
const http = require("http");
const express = require("express");
const app = express();
app.use((req, res, next) => {
console.log("In the middleware");
next();
});
app.use((req, res, next) => {
console.log("In another middleware");
res.send('<h3>sendMethod Done</h3>')
});
const server = http.createServer(app);
server.listen(3000);
const http = require("http");
const express = require("express");
const app = express();
app.use((req, res, next) => {
console.log("In the middleware");
res.send("<h2>First useFunction</h2>");
next();
});
app.use((req, res, next) => {
console.log("In another middleware");
res.send('<h2>Second useFunction</h2>')
});
const server = http.createServer(app);
server.listen(3000);
화면에 First useFunction
와 Second useFunction
을 모두 출력하고
싶으면 어떻게 해야 할까?
처음에는 First useFunction이 응답으로 출력이 돼고 next()
로 다음 미들웨어로 이동하니까 Second useFunction이 화면에 출력될것이라고 생각했다.
결과는 First useFunction만 출력이 돼고 다음 응답이 출력 돼지 않는다.
그 이유는 첫번째 미들웨어의 res.send('..')로 이미 응답을 보냈기 때문에 설령, 다음 미들웨어로 이동하였어도 브라우저는 또 응답을 보내지 않는것이다.
const http = require("http");
const express = require("express");
const app = express();
app.use((req, res, next) => {
console.log("In the middleware");
//res.send("<h2>First useFunction</h2>");
req.message = "<h2>First useFunction</h2>"
next();
});
app.use((req, res, next) => {
console.log("In another middleware");
//res.send('<h2>Second useFunction</h2>')
const fullMessage = req.message + "<h2>Second useFunction</h2>"
res.send(fullMessage);
});
app.listen(3000)
첫번째 미들웨어에서 출력할 문자를 문자열로 감싸 req.message
에 대입하고,
next()
로 다음 미들웨어로 이동하여 req.message
과 출력할 문자열을 연결하여 상수에 대입한다. 이때 코드상에서 두번째 미들웨어가 마지막 미들웨어임으로 응답객체를 반환해야 함으로 연결된 문자열을 응답 객체로 전송한다.
또한 아래의 코드를 app.listen(3000)
로 단축할 수 있는데
"express.js github"에 들어가보면, app.listen()에 내부적으로 서버를 설정하는 코드가 이미 들어있어 가능한 일이다.
const server = http.createServer(app);
server.listen(3000);
const express = require("express");
const app = express();
app.use('/add-product', (req, res, next) => {
console.log("In another middleware")
res.send('<form action="/product" method="POST"><input type="text" name="title"><button type="submit">Send</button></form>')
})
app.use('/product', (req, res, next) => {
console.log(req.body)
res.redirect('/')
})
app.use('/', (req, res, next) => {
console.log("In another middleware")
res.send('<h2>Second middleware</h2>')
})
app.listen(3000)
위 코드를 실행하여 보면 /add-product
url 경로로 접속한 경우 The Add-product
가 화면에 출력될 것이고 /
로 접속한경우 Second middleware
가 화면에 출력될 것이다. 나는 /add-product
경로로 접속시 사용자에게 어떤 값을 전송하도록 할 수 있게 /product
경로를 추가 하고 해당 경로는 또 최상위 경로로 redirect하는 코드를 구현하였다.
/product
에서 입력한 data가 잘 들어오는지 확인하기 위해 req.body
를 이용해 data를 확인해 본 결과 undefined
이 출력된다.
이유가 뭘까
req.은 들어오는 요청 본문에 대해 따로 분석하려 하지 않는다. 따라서 form 전송시 전송되어지는 본문 내용을 분석해야 한다.
npm install --save body-parser
로 package를 설치하고
상단과
add-product
경로 설정 위에 아래 코드를 출력하면 이제undefined
가 출력 돼지 않는다.
const bodyParser = require("body-parser")
app.use(bodyParser.urlencoded({extended: false}));
다수의 routing을 하는 함수를 모두 app.js파일에 작성하였는데, 이렇게 되면 app.js 파일 크기가 계속 커져서 보기가 어려울거라고 생각했고 각 기능별로 routing을 각 파일로 분리하고 싶었다.
Express에서 routes
폴더에 라우팅 하는 코드를 분리하여 파일구조를 다시 작성했다.
각 기능별 라우팅 파일을 생성하고 만든 route를 export하여 app.js에서 import하는 방식으로 변경하였다.
admin.js
const express = require('express')
const router = express.Router()
router.get('/add-product', (req, res, next) => {
res.send('<form action="/product" method="POST"><input type="text" name="title"><button type="submit">Send</button></form>')
})
router.post('/product', (req, res, next) => {
res.redirect('/')
})
module.exports = router
app.js
const express = require("express");
const bodyParser = require("body-parser")
const adminRoutes = require('./routes/admin')//import
const shopRoutes = require('./routes/shop')//import
const app = express();
app.use(bodyParser.urlencoded({extended: false}));
app.use(adminRoutes)
app.use(shopRoutes)
app.listen(3000)
.use()
에서 .get() / .post()
를 사용한 이유는 GET메서드임을 확인할 뿐만 아니라 해당 경로 페이지 접근시 해당 페이지는 GET기능만 가능하게 된다.
반면 .use를 이용하게 되는 경우 get/post/delete..등의 http method로의 모든 기능을 수행하게 된다.
이를통해 알수 있었던 것은 경로 매칭은 라우터를 통해서가 아니라 .get/.post../등의 메서드를 통해 이루어진다.