ํด๋ผ์ด์ธํธ๋ก๋ถํฐ ์ ๋ฌ๋ฐ์ ์ฟ ํค ๊ฒ์ฆ. ์ฟ ํค์์ ์ธ์ ์ด ๋ด๊ฒจ์๊ฑฐ๋ jwt๋ด๊ฒจ์์ผ๋ฉด ๊ทธ๊ฑธ ์ด์ฉํด ์ฌ์ฉ์ ์กฐํ๋ฅผ ํ์ฌ ๊ฒ์ฆํ๋ ๋ฏธ๋ค์จ์ด.
// src/middlewares/auth.middleware.js import jwt from 'jsonwebtoken'; import { prisma } from '../utils/prisma/index.js'; export default async function (req, res, next) { try { //1. ํด๋ผ์ด์ธํธ -> ์๋ฒ : ์ฟ ํค ์ ๋ฌ const { authorization } = req.cookies; if (!authorization) throw new Error('ํ ํฐ์ด ์กด์ฌํ์ง ์์ต๋๋ค.'); //2. ์ฟ ํค : Bearerํ ํฐ ํ์์ธ์ง ํ์ธ const [tokenType, token] = authorization.split(' '); if (tokenType !== 'Bearer') throw new Error('ํ ํฐ ํ์ ์ด ์ผ์นํ์ง ์์ต๋๋ค.'); //3. ์๋ฒ์์ ๋ฐ๊ธํ JWT ๋ง๋์ง ๊ฒ์ฆ const decodedToken = jwt.verify(token, 'secretKey'); const userId = decodedToken.userId; //4. JWT์ userId ์ด์ฉ -> ์ฌ์ฉ์ ์กฐํ const user = await prisma.users.findFirst({ where: { userId: Number(userId) }, }); if (!user) { //๋น์ ์์ ์ด๋๊น ์ฟ ํค ์ธ์ฆ์ ์คํจํ๋ฉด ํด๋น ํด๋ผ์ด์ธํธ์ ์ฟ ํค๋ฅผ ์ญ์ ํด์ค์ผํจ. res.clearCookie('authorization'); throw new Error('ํ ํฐ ์ฌ์ฉ์๊ฐ ์กด์ฌํ์ง ์์ต๋๋ค.'); } //5. req.user์ ์ฌ์ฉ์ ์ ๋ณด ํ ๋น req.user = user; //6. ๋ฏธ๋ค์จ์ด ์คํ next(); } catch (error) { //์ฟ ํค ์ธ์ฆ์ ์คํจํ๋ฉด ํด๋น ํด๋ผ์ด์ธํธ์ ์ฟ ํค๋ฅผ ์ญ์ ํด์ค์ผํจ. res.clearCookie('authorization'); // ํ ํฐ์ด ๋ง๋ฃ๋์๊ฑฐ๋, ์กฐ์๋์์ ๋, ์๋ฌ ๋ฉ์์ง๋ฅผ ๋ค๋ฅด๊ฒ ์ถ๋ ฅํฉ๋๋ค. switch (error.name) { case 'TokenExpiredError': return res.status(401).json({ message: 'ํ ํฐ์ด ๋ง๋ฃ๋์์ต๋๋ค.' }); case 'JsonWebTokenError': return res.status(401).json({ message: 'ํ ํฐ์ด ์กฐ์๋์์ต๋๋ค.' }); default: return res .status(401) .json({ message: error.message ?? '๋น์ ์์ ์ธ ์์ฒญ์ ๋๋ค.' }); } } }
ํด๋ผ์ด์ธํธ์ ๋ชจ๋ ์์ฒญ ์ฌํญ์ ๊ธฐ๋ก -> ์๋ฒ์ ์ํ ๋ชจ๋ํฐ๋ง ํ๊ธฐ ์ํ ๋ฏธ๋ค์จ์ด.
๋ค์ํ ๋ก๊ทธ๋ ๋ฒจ์ ์ด์ฉํ์ฌ ํน์ ์ํฉ์ ๋ฐ๋ผ ์ถ๋ ฅํ๋ ๋ ๋ฒจ์ ๋ค๋ฅด๊ฒ ๊ตฌํ ๊ฐ๋ฅ.
5๋จ๊ณ : silly
4๋จ๊ณ : debug
3๋จ๊ณ : verbose
2๋จ๊ณ : info
1๋จ๊ณ : warn
0๋จ๊ณ : error
๋จ๊ณ๋ณ๋ก ์์ ๋ฟ๋ง ์๋๋ผ ๊ทธ ์๋์ ๋ก๊ทธ๊น์ง ํํํ๋ค. (์์: info๋จ๊ณ๋ฅผ ์ค์ ํ๋ค๊ณ info๋ง ๋์ค๋๊ฒ ์๋๋ผ info, warn, error๊น์ง ๋ก๊ทธ ํํ์ด ๊ฐ๋ฅํจ)
winston ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ด์ฉ.
# yarn์ ์ด์ฉํด winston์ ์ค์น yarn add winston
// ํด๋ผ์ด์ธํธ์ ์์ฒญ์ ํฐ๋ฏธ๋์ ๊ธฐ๋กํ๋ ๊ฐ๋จํ ๋ก๊ทธ ๋ฏธ๋ค์จ์ด // src/middlewares/log.middleware.js import winston from 'winston'; const logger = winston.createLogger({ level: 'info', // ๋ก๊ทธ ๋ ๋ฒจ์ 'info'๋ก ์ค์ format: winston.format.json(), // ๋ก๊ทธ ํฌ๋งท์ JSON ํ์์ผ๋ก ์ค์ transports: [ new winston.transports.Console(), // ๋ก๊ทธ๋ฅผ ์ฝ์์ ์ถ๋ ฅ ], }); export default function (req, res, next) { // ํด๋ผ์ด์ธํธ์ ์์ฒญ์ด ์์๋ ์๊ฐ์ ๊ธฐ๋กํฉ๋๋ค. const start = new Date().getTime(); // ์๋ต์ด ์๋ฃ๋๋ฉด ๋ก๊ทธ๋ฅผ ๊ธฐ๋กํฉ๋๋ค. res.on('finish', () => { const duration = new Date().getTime() - start; logger.info( `Method: ${req.method}, URL: ${req.url}, Status: ${res.statusCode}, Duration: ${duration}ms`, ); }); next(); }
// src/app.js import LogMiddleware from './middlewares/log.middleware.js'; app.use(LogMiddleware); //๋ก๊ทธ๋ฏธ๋ค์จ์ด๋ ๋ค๋ฅธ ๋ฏธ๋ค์จ์ด๋ณด๋ค ๋จผ์ ์คํ๋์ด์ผํจ.
[์ฐธ๊ณ ์๋ฃ] https://coding8.tistory.com/39 https://ivvve.github.io/2020/05/31/js/js/winston-02-logging-level/
express.js์์ ๋ฐ์ํ ์์ด๋ฅผ ํตํฉ์ ์ผ๋ก ์ฒ๋ฆฌํ๊ธฐ ์ํ ๋ฏธ๋ค์จ์ด
// src/middlewares/error-handling.middleware.js export default function (err, req, res, next) { // ์๋ฌ๋ฅผ ์ถ๋ ฅํฉ๋๋ค. console.error(err); // ํด๋ผ์ด์ธํธ์๊ฒ ์๋ฌ ๋ฉ์์ง๋ฅผ ์ ๋ฌํฉ๋๋ค. res.status(500).json({ errorMessage: '์๋ฒ ๋ด๋ถ ์๋ฌ๊ฐ ๋ฐ์ํ์ต๋๋ค.' }); }
//API ํ์ผ ๋ด try catch๋ฌธ ์ค err๋ฅผ ์๋์ ๊ฐ์ด next(err)๋ก ๋๊ฒจ์ค๋ค. } catch (err) { next(err); } });
// src/app.js import ErrorHandlingMiddleware from './middlewares/error-handling.middleware.js'; app.use(LogMiddleware); app.use(express.json()); app.use(cookieParser()); app.use('/api', [UsersRouter]); app.use(ErrorHandlingMiddleware); //์๋ฌ๋ฏธ๋ค์จ์ด๋ ๋งจ ๋ง์ง๋ง์ ์์นํด์ผํจ!