웹개발 부트캠프 2022 4주차(자바스크립트)

백민철·2022년 5월 19일
0
post-thumbnail

(5/6 ~5/19) The Web Developer 부트캠프 2022 강의 내용 정리
범위 : YelpCamp CURD ~ Express와 Mongo연결하기(섹션 41 ~43)

미들웨어

미들웨어는 요청에서 응답 사이에 실행되는 함수이고 요청 객체와 응답 객체에 접근 및 수정할 수 있다.

Express는 라우팅과 최소한의 기능을 갖춘 미들웨어 웹 프레임워크의 결합이다
즉, Express 앱은 미들웨어 함수 호출의 연쇄일 뿐이다

Morgan

request logger middleware이다. 각종 Request 요청에 대한 간략한 정보들을 콘솔에 출력해주는 역할을 한다.

app.use(morgan('tiny'));
//dev 옵션
app.use(morgan('dev'));
//common 옵션
app.use(morgan('common'));

//tiny
GET / 200 9 - 3.296 ms
GET /favicon.ico 404 150 - 3.272 ms

//dev
GET / 304 4.349 ms - -

//common
::1 - - [18/May/2022:14:23:40 +0000] "GET / HTTP/1.1" 304 -

미들웨어 정의

app.use((req,res,next)=>{}) 형태로 정의하며 next함수를 통해 다음 미들웨어 또는 라우트 핸들러를 호출한다.

app.use((req, res, next) => {
    console.log('ThIS IS MY FIRST MIDDLEWARE!');
    next();
});
app.use((req, res, next) => {
    console.log('ThIS IS MY SECOND MIDDLEWARE!');
    req.requestTime = Date.now();
    next();
});

//미들웨어에서 요청이 들어온 시간을 요청객체의 requestTime에 넣어주어 라우트핸들러에서 접근할 수 있게 함
app.get('/', (req, res) => {
    console.log(req.requestTime);
    res.send('HOME PAGE');
});

404 경로 설정

라우트 핸들러 마지막에 미들웨어를 추가하여 어떤 요청에도 매칭되지 않을 경우 동작하도록 한다.

app.get(...)
app.get(...)

app.use((req,res)=>{
    res.status(404).send("Not Found");
})

미들웨어 패스워드 설정 데모

미들웨어에서 패스워드를 검사하여 일치하지 않는 패스워드일 경우 요청이 거부되도록 할 수 있다.
이를 토대로 특정 라우트에서 패스워드 확인을 하도록 할 수도 있다.

app.use((req, res, next) => {
    const { password } = req.query;
    if (password === 'secret') next();
    res.send('Sorry YOU NEED A PASSWORD');
});

app.get(...)

특정 라우트에서 패스워드 확인을 하는 경우

const verifyPassword = (req, res, next) => {
    const { password } = req.query;
    if (password === 'secret') next();
    res.send('Sorry YOU NEED A PASSWORD');
};
//라우트 핸들러 2번째 인자에 미들웨어를 추가해주면 된다.
app.get('/', verifyPassword, (req, res) => {});

ejs-mate

상용구를 사용할 수 있게 해주는 툴이다.
view파일에서 <% layout('layouts/boilerplate') %> 로 선언하면
해당 view파일은 <%- body%> 여기에 들어가게 된다. 그렇게 되면 아래에
BEFORE , AFTER가 상용구가 되어 공통적으로 쓰일 수 있게 된다.

<!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>BOILERPLATE!!!</title>
    </head>
    <body>
        <h1>BEFORE</h1>
        <%- body%>
        <h1>AFTER</h1>
    </body>
</html>
<% layout('layouts/boilerplate') %>

<h1>Edit Campground</h1>
<form action="/campgrounds/<%=campground.id%>?_method=PUT" method="POST">
    <div>
        <label for="title">Title</label>
        <input type="text" id="title" name="campground[title]" value="<%=campground.title%>" />
    </div>
    <div>
        <label for="location">Location</label>
        <input
            type="text"
            id="location"
            name="campground[location]"
            value="<%=campground.location%>"
        />
    </div>
    <button>Update Campground</button>
</form>
<a href="/campgrounds/<%=campground.id%>">Back To Campground</a>

Express 디폴트 오류 처리기

내장된 오류 핸들러가 앱에서 발생한 모든 오류를 처리한다.
오류 객체를 찾은 다음 상태 코드와 상태 메시지를 찾는다.
상태코드의 디폴트는 500이지만 바꿀 수 있다.

내장된 오류 핸들러만으로는 모든 오류를 처리할 수 없기에 다양한 유형에 대한
오류 핸들러를 추가하여야 한다.

예를 들면 Mongoose에서 유효성 오류가 발생한 경우 구문 오류나 인증 오류와는 다른 방법으로 처리해야한다.

사용자 지정 오류 처리기 정의

app.use((err, req, res, next) => {
    console.log('ERROR!');
    res.status(500).send('Oh! Error!');
    //내장된 오류 처리기를 사용하고 싶으면 next함수 호출 이 때 인수로 err를 전달해야한다.
    //express는 next에 무언가를 전달하면 현재 요청을 오류로 간주하여 남아 있는 오류 처리에 대한 동작만 한다.
});

사용자 지정 오류 클래스

오류에 대한 상태 코드와 메세지를 정해주는 작업을 각기 다른 상황에서 발생하는 모든 오류에 다 처리하려면 번거롭기에 이를 클래스로 만들은 것

class AppError extends Error {
    constructor(message, status) {
        super();
        this.message = message;
        this.status = status;
    }
}

const verifyPassword = (req, res, next) => {
    const { password } = req.query;
    if (password === 'secret') next();

    throw new AppError('password required', 401);
};

app.use((err, req, res, next) => {
    const { status = 500 } = err; //오류에 상태코드가 없을 경우 디폴트를 500으로 설정
    const { message = 'Something Went Wrong' } = err;
    res.status(status).send(message);
});

비동기 오류 처리하기

라우트 핸들러와 미들웨어에 의해 발동된 비동기 함수에서 반환된 오류의 경우에는
다음 함수로 전달하여 Express가 잡아내서 처리할 수 있게 해야 한다. 그렇지 않으면
오류 핸들러가 작동되지 않는다.

app.get('/products/:id', async (req, res, next) => {
    const product = await Product.findById(id);
    if (!product) {
        return next(new AppError('Product Not Found', 404));
    }
    //next가 호출되더라도 next다음 코드의 실행은 중단되지 않기 때문에 return이나 else로
    //정상 응답인 경우의 코드가 실행되지 않도록 해야한다.
    res.render('products/show', { product });
});

try-catch로 비동기 오류 처리

비동기 함수에서는 모든 걸 try...catch 문으로 감싸야 한다.
비동기 함수일 때만 해당이 되고 다른 경우엔 Express가 처리하기에 예를 들어 new를 render할 땐
try...catch 문으로 감쌀 필요가 없다.

app.get('/products/:id', async (req, res, next) => {
    try {
        const product = await Product.findById(id);

        if (!product) {
            throw new AppError('Product Not Found', 404);
        }

        res.render('products/show', { product });
    } catch (e) {
        next(e);
    }
});

비동기 유틸리티 정의

try...catch 문을 모든 각각의 비동기 라우트 콜백 그리고 핸들러와 미들웨어 등에
일일이 추가하는 것은 번거롭기에 이를 해결하고자 wrapAsync라는 함수를 정의하여 사용한다.
이 함수는 함수를 전달받아 catch메소드를 체인하여 에러가 발생할 경우 next함수를 호출하도록 한다.

function wrapAsync(fn) {
    return function (req, res, next) {
        fn(req, res, next).catch((e) => next(e));
    };
}

app.get(
    '/products/:id',
    wrapAsync(async (req, res, next) => {
        const product = await Product.findById(id);

        if (!product) {
            throw new AppError('Product Not Found', 404);
        }

        res.render('products/show', { product });
    })
);

Express 5부터 Promise를 반환하는 라우트 핸들러 및 미들웨어는 거부하거나 오류를 던질 때 자동으로 next(value) 호출 한다.

$ npm install express@next //최신 버전의 express v5 알파 버전 설치

express5에서 비동기 오류 처리 예시

app.get('/user/:id', async function (req, res, next) {
    var user = await getUserById(req.params.id);
    res.send(user);
});

Mongoose 오류 구분하기

모든 Mongoose 오류에는 name이라는 특성이 있다. 이를 활용하여 오류 처리 미들웨어에서 오류마다 handle에러처리 함수를 호출하게할 수 있다.

  • Mongoose 오류 종류

    • ValidationError 유효성 검사 오류
    • CastError 캐스트 오류
const handleValidationErr=(err){
    console.dir(err)
    return new AppError(`Validation Failed...${err.message}`,400)
}


app.use((err, req, res, next) => {
    if (err.name === 'ValidationError') err = handleValidationErr(err);
    next(err);
});

Joi

자바스크립트 유효성 검사 도구이다.

0개의 댓글