[Node] MiddleWare

silverKi·2023년 12월 15일
0

Node

목록 보기
2/6

MiddleWare가 뭘까

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()를 제거하면 서버는 첫번째 미들웨어에 머무를 것이고 어떠한 응답객체를 전송하지 않았기 때문에 무한로딩 또는 무한 대기 상태에 빠지게 된다.
만약 미들웨어가 여러개인 경우, 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.send()와 res.write()와 무엇이 다른가?

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 useFunctionSecond 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);


MiddleWare로 라우팅하기

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../등의 메서드를 통해 이루어진다.


profile
아악! 뜨거워!!

0개의 댓글