Skip to content

Latest commit

ย 

History

History
334 lines (265 loc) ยท 10.3 KB

README-default.md

File metadata and controls

334 lines (265 loc) ยท 10.3 KB

1. express-generator์„ ์ด์šฉํ•œ ํ”„๋กœ์ ํŠธ ํด๋” ์ƒ์„ฑ

  • express ํ”„๋กœ์ ํŠธ ํด๋” ์ƒ์„ฑ
  • ejs ์ ์šฉ

$ express --ejs ํ”„๋กœ์ ํŠธ์ด๋ฆ„

2. .gitignore ํŒŒ์ผ ์ถ”๊ฐ€

  • ์‹ค์ œ ํ”„๋กœ์ ํŠธ ์ง„ํ–‰ ์‹œ์—๋Š”, .gitignore์— #### ์ง์ ‘ ์„ค์ •ํ•œ Gitignore ####๋กœ ์ฃผ์„ ์ฒ˜๋ฆฌ ๋˜์–ด ์žˆ๋Š” ๋ฐ‘ ๋ถ€๋ถ„์˜ ์ฝ”๋“œ์— ๋Œ€ํ•ด ์ฃผ์„์ฒ˜๋ฆฌ ํ•ด์ œํ•˜๊ธฐ
  • .env ์ฃผ์„ ์ฒ˜๋ฆฌ ๋˜์–ด ์žˆ๋Š” ๋ถ€๋ถ„ ํ•ด์ œํ•˜๊ธฐ

3. ๋ผ์šฐํŒ… ๊ด€๋ จ ํด๋” ๊ตฌ์กฐ ์…‹ํŒ…

  • index.js๋ฅผ ํ™œ์šฉํ•œ ๋ผ์šฐํŒ… ํด๋” ๋‚˜๋ˆ„๊ธฐ

๊ด€๋ จ ํด๋” ๋ฐ ํŒŒ์ผ

  • app.js ํŒŒ์ผ
  • routes ํด๋”

4. dotenv ํŒจํ‚ค์ง€ ์„ค์น˜

  • ํŠน์ • ํ‚ค๋ฅผ ํ•˜๋“œ์ฝ”๋”ฉํ•˜๋ฉด ์†Œ์Šค ์ฝ”๋“œ๊ฐ€ ์œ ์ถœ๋˜์—ˆ์„ ๋•Œ ํ‚ค๋„ ๊ฐ™์ด ์œ ์ถœ๋˜๋ฏ€๋กœ ๋ณ„๋„๋กœ ๊ด€๋ฆฌํ•ด์•ผ ํ•œ๋‹ค. ์ด๋ฅผ ์œ„ํ•œ ํŒจํ‚ค์ง€๊ฐ€ dotenv์ด๋‹ค. ๋น„๋ฐ€ํ‚ค๋Š” .env๋ผ๋Š” ํŒŒ์ผ์— ๋ชจ์•„๋‘๊ณ , dotenv๊ฐ€ .env ํŒŒ์ผ์„ ์ฝ์–ด process.env(ํ™˜๊ฒฝ๋ณ€์ˆ˜) ๊ฐ์ฒด์— ๋„ฃ๋Š”๋‹ค.

์„ค์น˜ ๋ฐฉ๋ฒ•

$ npm i dotenv

๊ด€๋ จ ํด๋” ๋ฐ ํŒŒ์ผ

  • app.js ํŒŒ์ผ
  • .env ํŒŒ์ผ

5. ๋ณด์•ˆ ์ถ”๊ฐ€ : helmet, hpp ์„ค์ •

์„ค์น˜ ๋ฐฉ๋ฒ•

$ npm i helmet hpp

๊ด€๋ จ ํด๋” ๋ฐ ํŒŒ์ผ

  • app.js ํŒŒ์ผ

์ฐธ๊ณ 

6. morgan, winston์„ ํ™œ์šฉํ•œ ๋กœ๊ทธ ๊ธฐ๋ก ๋‚จ๊ธฐ๊ธฐ

  • log/server/combined ํด๋”์— 1์‹œ๊ฐ„ ๋‹จ์œ„๋กœ ๋กœ๊ทธ ํŒŒ์ผ์ด ๋‚จ์„ ๊ฒƒ์ด๋‹ค.
  • log/server/error ํด๋”์— ํ•˜๋ฃจ ๋‹จ์œ„๋กœ ๋กœ๊ทธ ํŒŒ์ผ์ด ๋‚จ์„ ๊ฒƒ์ด๋‹ค.

๋กœ๊ทธ ์ €์žฅ ํ˜•์‹

  • $ npm run production์œผ๋กœ ์‹คํ–‰์‹œํ‚ฌ ๋•Œ, ๋กœ๊ทธ๊ฐ€ ๊ธฐ๋ก๋œ๋‹ค.
  • log/server/combined ํด๋”์™€ log/server/error ํด๋”์— ๋กœ๊ทธ ํŒŒ์ผ๋“ค์ด ์ €์žฅ๋œ๋‹ค.

a) ์ผ๋ฐ˜ ๋ผ์šฐํŒ… ํ†ต์‹  ์‹œ ์ €์žฅ๋˜๋Š” ๋กœ๊ทธ์˜ ํ˜•ํƒœ

  • ํ˜•ํƒœ : ${๋‚ ์งœ ๋ฐ ์‹œ๊ฐ„} [${๋กœ๊ทธ ์ข…๋ฅ˜}] ์š”์ฒญ์ž ip = ${์š”์ฒญ์ž ip} || ${HTTP Method ์ข…๋ฅ˜} ${HTTP ํ†ต์‹  ์ฃผ์†Œ} ${์‘๋‹ต ์ฝ”๋“œ} ${์‘๋‹ต ์‹œ๊ฐ„} || ์ด์ „ url = ${์ด์ „ url}
2020-03-02 11:04:47 [INFO] ์š”์ฒญ์ž ip = 211.111.111.11:34974 || GET /webview/kakao_map 304 140.744 ms || ์ด์ „ url = -

b) ์—๋Ÿฌ ๋ฐœ์ƒ ์‹œ ์ €์žฅ๋˜๋Š” ๋กœ๊ทธ์˜ ํ˜•ํƒœ

2020-02-28 08:38:21 [ERROR] Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
    at ServerResponse.setHeader (_http_outgoing.js:470:11)

์„ค์น˜ ๋ฐฉ๋ฒ•

$ npm i winston winston-daily-rotate-file

๊ด€๋ จ ํด๋” ๋ฐ ํŒŒ์ผ

  • app.js ํŒŒ์ผ
  • module/winston.js ํŒŒ์ผ

7. error_handling ์—๋Ÿฌ ์ฒ˜๋ฆฌ ๋ชจ๋“ˆ ์ถ”๊ฐ€

  • ๋ฐœ์ƒํ•œ ์—๋Ÿฌ์— ๋Œ€ํ•ด์„œ winston์„ ํ™œ์šฉํ•ด ๋กœ๊ทธ ํŒŒ์ผ๋กœ ๊ธฐ๋ก
  • ์ผ๋ฐ˜์ ์ธ ๊ฒฝ์šฐ ์—๋Ÿฌ ์ฒ˜๋ฆฌ ๊ฐ€๋Šฅ
  • sequelize transaction ์—๋Ÿฌ ์ฒ˜๋ฆฌ ๊ฐ€๋Šฅ
  • axios๋กœ ์ธํ•œ ์—๋Ÿฌ ์ฒ˜๋ฆฌ ๊ฐ€๋Šฅ
  • token์— ๋”ฐ๋ฅธ ์—๋Ÿฌ ์ฒ˜๋ฆฌ ๊ฐ€๋Šฅ
  • GraphQL ํ†ต์‹  ์—๋Ÿฌ ์ฒ˜๋ฆฌ ๊ฐ€๋Šฅ

์‚ฌ์šฉ ์˜ˆ์‹œ

// ํŒŒ์ผ๋ช… : routes/daly/v2/region/region.js
var express = require('express');
var router = express.Router();
const error_handling = require('../../../../module/error_handling');

router.get('/', async (req, res) => {
    try {
        ...
    } catch (err) {
        error_handling.normal(err, res, transaction);
    }
});
module.exports = router;

๊ด€๋ จ ํด๋” ๋ฐ ํŒŒ์ผ

  • module/error_handling.js

8. response ๋ชจ๋“ˆ

  • ํด๋ผ์ด์–ธํŠธํ•œํ…Œ ์ผ๊ด€๋œ ํ˜•ํƒœ๋กœ ์‘๋‹ต ์ฝ”๋“œ์™€ ์‘๋‹ต ๋ฉ”์‹œ์ง€๋ฅผ ๋ณด๋‚ด๊ธฐ ์œ„ํ•œ ๋ชจ๋“ˆ

์‚ฌ์šฉ ์˜ˆ์‹œ

var express = require('express');
var router = express.Router();
const error_handling = require('../../../../module/error_handling');

router.get('/', async (req, res) => {
    try {
        ...
        res.status(200).json(response(resMessage.EXPIRED_TOKEN));
    } catch (err) {
        ...
    }
});
module.exports = router;

๊ด€๋ จ ํด๋” ๋ฐ ํŒŒ์ผ

  • module/response/index.js
  • module/response/message.js

9. Sequelize ํ™˜๊ฒฝ ์„ค์ • ์…‹ํŒ… ๋ฐ ๋ชจ๋ธ ์…‹ํŒ… (DB ์„ค๊ณ„)

์„ค์น˜ ๋ฐฉ๋ฒ•

$ npm i sequelize

์…‹ํŒ… ํ•ด์•ผ ํ•  ๋ถ€๋ถ„

  • config/sequelize/dbConfig.json ํŒŒ์ผ์—์„œ ์—ฐ๊ฒฐ์‹œํ‚ฌ DB ๊ด€๋ จ ์ •๋ณด๋ฅผ ์ž…๋ ฅํ•ด์•ผ ํ•œ๋‹ค.
  • models ํด๋”์—์„œ ์ •์˜ํ•  DB ํ…Œ์ด๋ธ”์— ๋Œ€ํ•ด์„œ ์„ ์–ธํ•ด์ฃผ์–ด์•ผ ํ•œ๋‹ค.

์‚ฌ์šฉ ์˜ˆ์‹œ

var express = require('express');
var router = express.Router();
const { Sequelize, Sequelize: { Op }, sequelize, User, Store, Store_img, 
        Product, Product_img, Banner, Payment_history, Category, Category_product, Hashtag, 
        Hashtag_product, Precaution, Banner_btn, Banner_sub_img } = require('../../../../models');

router.delete('/', async(req, res) => {
    try {
        ...
        const result = await Store.destroy({
            where: {
                id
            },
            transaction
        })
        ...
    } catch(err) {
        ...
    }
});

module.exports = router;

๊ด€๋ จ ํด๋” ๋ฐ ํŒŒ์ผ

  • app.js ํŒŒ์ผ
  • models ํด๋”
  • config/sequelize/dbConfig.json ํŒŒ์ผ

10. multer, AWS S3, AWS IAM

์…‹ํŒ… ํ•ด์•ผ ํ•  ๋ถ€๋ถ„

  • config/awsconfig.json์— AWS IAM์˜ access key์™€ access key secret์„ ์ž…๋ ฅํ•ด์•ผ ํ•œ๋‹ค.
  • config/multer.js์— S3 bucket ์ด๋ฆ„์„ ์ž…๋ ฅํ•ด์•ผ ํ•œ๋‹ค.

์‚ฌ์šฉ๋ฒ•

  • ๋ผ์šฐํŒ…์—์„œ multer์— ๋Œ€ํ•œ ์ž์„ธํ•œ ์‚ฌ์šฉ๋ฒ•์€ multer Docs์„ ์ฐธ๊ณ ํ•ด๋ผ.

์‚ฌ์šฉ ์˜ˆ์‹œ

var express = require('express');
var router = express.Router();
const response = require('../../../module/response');
const resMessage = require('../../../module/response/message');
const upload = require('../../../config/multer');
const logger = require('../../../config/winstonConfig');

// ์ƒํ’ˆ ๋“ฑ๋ก
router.post('/', jwt.isLoggedIn, (req, res, next) => {
    upload.array('images', 10)(req, res, function (err) {
        if (err) {
            if (err.code === 'LIMIT_FILE_SIZE') {
                // ํŒŒ์ผ ์ œํ•œ ์šฉ๋Ÿ‰์„ ๋„˜์€ ๊ฒฝ์šฐ
                logger.log('error', err.stack);
                res.status(200).json(response(resMessage.LIMIT_FILE_SIZE));
            } else {
                // console.log('multer์˜ ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ์—๋Ÿฌ');
                logger.log('error', err.stack);
                res.status(200).json(response(resMessage.INTERNAL_SERVER_ERROR));
            }
        } else {
            next()
        }
})}, async(req, res) => {
    try {
        ...
    } catch(err) {
        ...
    }
});
module.exports = router;

๊ด€๋ จ ํด๋” ๋ฐ ํŒŒ์ผ

  • config/awsconfig.json
  • config/multer.js

11. JWT ๋ชจ๋“ˆ ์…‹ํŒ…

์…‹ํŒ…

  • module/auth/jwt.js ํŒŒ์ผ์—์„œ process.env.JWT_SECRET, process.env.JWT_REFRESH_TOKEN_SECRET์„ ์ธ์‹ํ•  ์ˆ˜ ์žˆ๋„๋ก .env ํŒŒ์ผ์— ๋ณ€์ˆ˜๋ฅผ ์„ ์–ธํ•ด์ค˜์•ผ ํ•œ๋‹ค.

์‚ฌ์šฉ ์˜ˆ์‹œ

var express = require('express');
var router = express.Router();
const jwt = require('../../../module/auth/jwt');

router.get('/', jwt.isLoggedIn, async(req, res) => {
    try {
        ...
    } catch(err) {
        ...
    }
});

module.exports = router;

๊ด€๋ จ ํด๋” ๋ฐ ํŒŒ์ผ

  • module/auth/jwt.js

12. crypto ๋ชจ๋“ˆ ์…‹ํŒ…

  • ์•”ํ˜ธํ™” ์‹œํ‚ค๋Š” ๋ฐ ์‚ฌ์šฉ (์ฃผ๋กœ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์•”ํ˜ธํ™” ์‹œํ‚ค๋Š” ๋ฐ ์‚ฌ์šฉ)

์‚ฌ์šฉ ์˜ˆ์‹œ

var express = require('express');
var router = express.Router();
const response = require('../../../module/response');
const resMessage = require('../../../module/response/message');
const cryptoPassword = require('../../../module/auth/cryptoPassword');
const jwt = require('../../../module/auth/jwt');
const { sequelize, User, Marketing } = require('../../../models');
const logger = require('../../../config/winstonConfig');
const error_handling = require('../../../module/error_handling');


// ๋กœ๊ทธ์ธ
router.post('/', async(req, res) => {
    try {
        // ํŠธ๋žœ์žญ์…˜ ์ฒ˜๋ฆฌ
        var transaction = await sequelize.transaction();
        
        let { email, password } = req.body;

        // Params๋‚˜ Body๊ฐ’์— ํ•„์ˆ˜์ ์œผ๋กœ ๋“ค์–ด์™€์•ผ ํ•˜๋Š” ๊ฐ’์ด ๋“ค์–ด์˜ค์ง€ ์•Š์€ ๊ฒฝ์šฐ
        if (!email || !password) {
            res.status(200).json(response.failure(resMessage.NULL_VALUE));
        } else {
            // users์˜ user_id, email, name ์ •๋ณด ๋ถˆ๋Ÿฌ์˜ค๊ธฐ
            const result = await User.findOne({ 
                where: { 
                    email,
                    provider: 'local'
                },
                attributes: ['id', 'name', 'email', 'birth', 'gender', 'createdAt', 'updatedAt', 'deletedAt', 'salt', 'password', 'role'],
                include: [{
                    model: Marketing,
                    attributes: ['is_third_party_agreement', 'is_event_alarm']
                }],
                transaction
            });
            // console.log('ํ…Œ์ŠคํŠธ : ', result);
            
            // ์กด์žฌํ•˜์ง€ ์•Š๋Š” ์•„์ด๋””์˜ ๊ฒฝ์šฐ
            if (result === null) {
                res.status(200).json(response.success(resMessage.NULL_USER));

            // ์กด์žฌํ•˜๋Š” ์•„์ด๋””์ธ ๊ฒฝ์šฐ
            } else {
                const salt = result.dataValues.salt;
                const db_hashed_password = result.dataValues.password;
                const hashed_password = await cryptoPassword.hashedPassword(password, salt); 
                // ํŒจ์Šค์›Œ๋“œ๊ฐ€ ์ผ์น˜ํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ
                if (db_hashed_password !== hashed_password) {
                    res.status(200).json(response.success(resMessage.INVALID_PASSWORD));

                // ํŒจ์Šค์›Œ๋“œ๊ฐ€ ์ผ์น˜ํ•˜๋Š” ๊ฒฝ์šฐ -> ๋กœ๊ทธ์ธ ์„ฑ๊ณต
                } else {
                    const token = jwt.sign(result.dataValues);
                    const refresh_token = jwt.refresh_token_sign(result.dataValues);

                    // ๋ฆฌํ”„๋ ˆ์‹œ ํ† ํฐ ์ €์žฅ         
                    const response_ = await User.update({
                        refresh_token
                    }, {
                        where: { id: result.dataValues.id },
                        transaction
                    });
                    // console.log('๋ฆฌํ”„๋ ˆ์‹œ ํ† ํฐ ์ €์žฅ ์—ฌ๋ถ€ : ', response_);

                    // ํด๋ผ์ด์–ธํŠธํ•œํ…Œ ํ† ํฐ๊ณผ ๋ฆฌํ”„๋ ˆ์‹œ ํ† ํฐ ์ „์†ก
                    let data = {
                        token,
                        refresh_token
                    };
                    
                    res.status(200).json(response.success(resMessage.LOGIN_SUCCESS, data));
                }
            }
        }
        await transaction.commit();
    } catch(err) {
        error_handling.normal(err, res, transaction);
    }
});

module.exports = router;

๊ด€๋ จ ํด๋” ๋ฐ ํŒŒ์ผ

  • module/auth/cryptoPassword.js