클라우드 20일차 : mini project

soso·2024년 7월 5일

클라우드 부트캠프

목록 보기
22/77

프로젝트 보안 고려사항, 보강 시나리오 2를 목표

캐시 사용

사용자의 거래 내역을 불러올때마다 DB를 연결해 받아오거나 클라이언트에서 모든 내역을 저장해두고 정렬하거나 페이징 하는 기존 코드를
프론트엔드 서버에서 캐시를 사용하여 서버 연결 후 처음으로 거래 내역을 불러올때 DB에서 받아오면서 캐시에 저장하여 거래 내역이 추가(입출금, 송금 등)되지 않는 이상 저장된 캐시를 사용해 클라이언트에게 응답하는 코드로 수정

asset-management.js(Frontend)
수정 전

// 자산관리 거래 내역 불러오기
router.get('/transactions', async function (req, res) {
    try {
        const response = await fetch(`http://127.0.0.1:8000/amm/transactions`, {
            method: 'GET',
            headers: {
                'Content-Type': 'application/json',
                'User-Id': req.session.user.userid
            }
        });
        const data = await response.json();
        if (response.ok) {
            res.json(data);
        } else {
            res.status(response.status).json(data);
        }
    } catch (error) {
        console.error(error);
        res.status(500).json({ message: '서버 오류가 발생했습니다.' });
    }
});

수정 후

// 자산관리 거래 내역 불러오기
// 캐시가 존재하면 DB에 접근하지 않고 저장된 캐시를 사용해 응답
router.get('/transactions', async function (req, res) {
    const userId = req.session.user.userid;
    const accountNumber = req.query.account;
    const transactionType = req.query.filter || 'all';
    const page = parseInt(req.query.page) || 1;
    const rowsPerPage = 10;

    let transactions = transactionCache.get(userId);

    if (!transactions) {
        try {
            const response = await fetch(`http://127.0.0.1:8000/amm/transactions`, {
                method: 'GET',
                headers: {
                    'Content-Type': 'application/json',
                    'User-Id': userId,
                }
            });
            const data = await response.json();
            if (response.ok) {
                transactionCache.set(userId, data);
                transactions = data;
            } else {
                return res.status(response.status).json(data);
            }
        } catch (error) {
            console.error(error);
            return res.status(500).json({ message: '서버 오류가 발생했습니다.' });
        }
    }

    // 필터링
    let filteredTransactions = transactions;
    if (accountNumber && accountNumber !== '') {
        filteredTransactions = filteredTransactions.filter(transaction => transaction.account_number === accountNumber);
    }
    if (transactionType !== 'all') {
        filteredTransactions = filteredTransactions.filter(transaction => transaction.transaction_type === transactionType);
    }

    // 페이징
    const totalTransactions = filteredTransactions.length;
    const pageCount = Math.ceil(totalTransactions / rowsPerPage);
    const paginatedTransactions = filteredTransactions.slice((page - 1) * rowsPerPage, page * rowsPerPage);

    res.json({
        transactions: paginatedTransactions,
        page,
        pageCount,
        totalTransactions
    });
});

asset-management.js(Backend)

// 자산관리 거래 내역 불러오기
router.get('/transactions', async function (req, res) {
    const { mysqldb } = await setup();

    const sessionUser = req.headers['user-id'];

    if (!sessionUser) {
        return res.status(401).json({ message: '인증되지 않은 사용자' });
    }


    // const accountNumber = req.query.account || null;		// 필터링 코드 삭제
    // const transactionType = req.query.filter || 'all';


    try {
        // 사용자 ID로 계좌 정보 가져오기
        const [accounts] = await mysqldb.promise().query('SELECT account_number, user_id FROM accounts WHERE user_id = (SELECT id FROM users WHERE userid = ?)', [sessionUser]);

        if (accounts.length === 0) {
            return res.status(404).json({ message: '해당 사용자의 계좌를 찾을 수 없습니다.' });
        }



        // 계좌 번호가 있는 경우, 해당 계좌의 소유자 확인			// 필터링 코드 삭제
        // if (accountNumber) {
        //     const [account] = await mysqldb.promise().query('SELECT user_id FROM accounts WHERE account_number = ?', [accountNumber]);
        //     if (account.length === 0 || account[0].user_id !== accounts[0].user_id) {
        //         return res.status(403).json({ message: '해당 계좌에 접근 권한이 없습니다.' });
        //     }
        // }



        // 기본 쿼리
        let query = 'SELECT * FROM transactions WHERE account_number IN (SELECT account_number FROM accounts WHERE user_id = (SELECT id FROM users WHERE userid = ?))';
        const queryParams = [sessionUser];



        // if (accountNumber) {								// 필터링 코드 삭제
        //     query += ' AND account_number = ?';
        //     queryParams.push(accountNumber);
        // }
        //
        // if (transactionType !== 'all') {
        //     query += ' AND transaction_type = ?';
        //     queryParams.push(transactionType);
        // }



        query += ' ORDER BY transaction_date DESC';

        // 거래 내역 조회
        const [transactions] = await mysqldb.promise().query(query, queryParams);

        return res.status(200).json(transactions);
    } catch (err) {
        console.error(err);
        return res.status(500).json({ message: '서버 오류 발생' });
    }
});

기존 특정 계좌의 잔액 불러오는 코드도 캐시를 사용하도록 수정

asset-management.js(Frontend)

// 자산관리 특정 계좌의 잔액 불러오기
router.get('/account-balance/:accountNumber', async function (req, res) {
    const userId = req.session.user.userid;
    const accountNumber = req.params.accountNumber;
    const transactions = transactionCache.get(userId);

    if (transactions) {
        const accountTransactions = transactions.filter(transaction => transaction.account_number === accountNumber);
        if (accountTransactions.length > 0) {
            const latestTransaction = accountTransactions.reduce((latest, transaction) => {
                return new Date(transaction.transaction_date) > new Date(latest.transaction_date) ? transaction : latest;
            });
            return res.json({ balance: latestTransaction.balance });
        }
    }

    try {
        const response = await fetch(`http://127.0.0.1:8000/amm/account-balance/${accountNumber}`, {
            method: 'GET',
            headers: {
                'Content-Type': 'application/json',
                'User-Id': userId,
            }
        });
        const data = await response.json();
        if (response.ok) {
            res.json(data);
        } else {
            res.status(response.status).json(data);
        }
    } catch (error) {
        console.error(error);
        res.status(500).json({ message: '서버 오류가 발생했습니다.' });
    }
});

DB가 수정되면 캐시 초기화

asset-managemnet.js(Frontend)

// 자산관리 송금 처리
router.post('/transfer', async function (req, res) {
    try {
        const response = await fetch('http://127.0.0.1:8000/amm/transfer', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'User-Id': req.session.user.userid
            },
            body: JSON.stringify({ ...req.body })

        });
        const data = await response.json();
        if (response.ok) {
            transactionCache.del(req.session.user.userid); // 캐시 초기화
            res.status(201).send(data);
        } else {
            res.status(response.status).send(data);
        }
    } catch (error) {
        console.error(error);
    }
});

0개의 댓글