ํ์๊ฐ์
, ๋ก๊ทธ์ธ
๊ธ์ฐ๊ธฐ / ์กฐํ / ์์ / ์ญ์
์ข์์, ๋๊ธ
์ค์๊ฐ ์ฑํ
(socket io)
npm install multer multer -s3 mongoose socket.io jsonwebtoken bcrypt aws-sdk
# multer : ์ด๋ฏธ์ง ์
๋ก๋
# multer -s3, aws-sdk : ์ด๋ฏธ์ง ์
๋ก๋๋ฅผ ์ฐ๋ฆฌ ์๋ฒ๊ฐ ์๋๋ผ ์๋ง์กด S3 ์ ์ฅ์์ ์
๋ก๋ํ๊ธฐ ์ฝ๊ฒ ํด์ฃผ๋ ํจํค์ง.
# mongoose : mongoDB ์ฌ์ฉ์ ์ฝ๊ฒ ํด์ค.
# socket.io : ์ค์๊ฐ ์ฑํ
์๋ฒ๋ฅผ ์ฝ๊ฒ ํด์ฃผ๋!!
# jsonwebtoken : ๋ก๊ทธ์ธ ์ธ์
๋์ ์ฌ์ฉ์ ๋ก๊ทธ์ธ ์ธ์ฆ์ JWT ๋ก ์งํ
# bcrypt : ๋น๋ฐ๋ฒํธ ํด์ํจ์ ์ ์ฉ์ ์ํ ํจํค์ง
ํ๋ก ํธ์๋ ejs, css ํ์ผ์ ์ ๋ถ ๋ณต๋ถํ๊ณ (!!!) ๋ค์ด๊ฐ๋ค. ๋ฐฑ์๋ ๊ฐ์๋ผ์ ์์ธํ๋ ๋ชฐ๋ผ๋ ๋๋ค๊ณ ํ์ จ์ง๋ง... ์ฐ๋ฆฌ๋ ํ๋ก ํธ์๋ ๊ณผ์ ์ด๋๊น ์์์ผ๊ฒ ์ง... ๊ทธ์น๋ง ์๋ฒ ํ ์คํธ๋ฅผ ์ํ ๊ฐ๋จํ ๊ตฌ์กฐ์์ด์ ์ด๋ ค์ด ๊ตฌ์กฐ๋ ์์ ๋ฏ ํ๋ค! ejs ํ์ผ์ด๋ผ ์๋ฐ์คํฌ๋ฆฝํธ ๋ก์ง ๋ค์ด๊ฐ๋ ๋ถ๋ถ๋ง ๋ ๋ณด๋ฉด ๋ ๋ฏ!!
express ๊ธฐ๋ณธ ์ค์ ์ธ routes/users.js ์ญ์ , app.js์์ users.js ๊ด๋ จ ์ฝ๋ ์ญ์ ํ๋ค.
routes/auth/index.js, routes/posts/index.js ๋ก ํ์๊ฐ์ , ๋ก๊ทธ์ธ๊ณผ ๊ฒ์๋ฌผ ๊ด๋ จ ์ฝ๋๋ฅผ ๋ค๋ฅธ ํด๋๋ก ๊ด๋ฆฌํ๋ค. ๊ฐ๋ฐ ์ค์๋ ํ์ผ์ ์๋ค๊ฐ๋ค ํด์ผํด์
// routes/index.js
// ์ด์ ํ๋ก์ ํธ๋ app.js์ ๋ฐ๋ก ๋๋ ์ ์ฒ๋ฆฌ ํ์๋๋ฐ
// routes ํด๋๋ฅผ ์ ๋ฆฌํ๋ฉด์ app.js์์ ์ด๋ค ๋ก์ง์ด ํ์ํ ๋, index.js๋ก ๊ฐ๊ฒ ๋ง๋ค๊ณ ๊ฑฐ๊ธฐ์ ๋ค์ ๋๋๊ฒ ์ฒ๋ฆฌ๋ฅผ ํ๋ค.
var express = require('express');
var router = express.Router();
const authRouter = require('./auth');
const postRouter = require('./posts');
const postCtr = require('../controller/postCtr');
// ๊ฒ์๋ฌผ ๋ฆฌ์คํธ ์กฐํ : ๋ฉ์ธํ๋ฉด์ ๋ค์ด๊ฐ์๋ง์ ๊ฒ์๋ฌผ ๋ฆฌ์คํธ๊ฐ ๋จ๋๊น.
router.get("/", postCtr.list);
// auth, posts ๊ด๋ จ ๋ด์ฉ์ ํด๋น ๋ผ์ฐํฐ๋ก ์ด๋ํ๋๋ก.
router.use('/auth', authRouter);
router.use('/posts', postRouter);
module.exports = router;
// routes/auth/index.js
// ํ์๊ฐ์
, ๋ก๊ทธ์ธ ๊ด๋ จ ๋ก์ง์ ์ฒ๋ฆฌ.
const express = require("express");
const router = express.Router();
// ๋ก์ง์ ์์ง ๊ตฌํํ์ง ์์์ ํ์ด์ง๋ง ๋จผ์ ๋ณด์ฌ์ฃผ๋ ์์ผ๋ก ์ฒ๋ฆฌ.
router.get('/login', (req, res) => {
res.render("login");
});
router.get('/register', (req, res) => {
res.render("register");
});
module.exports = router;
// routes/posts/index.js
// ๊ฒ์๋ฌผ CRUD, ์ข์์, ๋๊ธ ๋ก์ง์ ๋ด๋น.
const express = require("express");
const { route } = require("..");
const router = express.Router();
// ์ญ์ ์์ง ๋ก์ง์ ์ง์ง ์์์ผ๋ฏ๋ก ํ๋ฉด์ ๋ณด์ฌ์ฃผ๊ธฐ๋ง ํ๋ค.
router.get('/upload', (req, res) => {
res.render('upload');
});
router.get('/:id', (req, res) => {
res.render('update');
});
module.exports = router;
์ด์ ๋ ํ์๊ธฐ ๋๋ฌธ์, ์์ธํ ์ค๋ช ์ ์๋ตํ๋ค.
// bin/www
const mongoose = require("mongoose");
const db = mongoose.connection;
db.on("error", console.error);
db.once("open", () => {
console.log("Connected to mongodb server!!");
});
mongoose.connect(
`mongodb+srv://ddosang:${dbConfig.password}@first-project.7rouh.mongodb.net/${dbConfig.name}?retryWrites=true&w=majority`
);
mongoDB์ ์ฅ์ ์ noSQL์ด์ง๋ง SQL์ฒ๋ผ ๋นก๋นกํ๊ฒ๋ ์๋๋๋ผ๋ ํ์์ ์ ํด๋์ด์ผ ์์ฒญ/์๋ต, ํ์ ๊ด๋ฆฌ๊ฐ ํธํ๊ธฐ ๋๋ฌธ์ ์ก์๋ค. ํฌ๊ฒ ๊ฒ์๋ฌผ ๊ด๋ จ ๋ชจ๋ธ๊ณผ ๋ก๊ทธ์ธ ๊ด๋ จ ๋ชจ๋ธ์ด ์๋๋ฐ, ์์ ๋ด์ฉ์ ๋ฐ๋ผ๊ฐ ๋๋ ์ ์ด๊ฑฐ ํ์ํ๊ฒ ๋ค~ ์ถ์๋ฐ ํผ์ ์ง๋ณด๋ฉด ๋ญ๊ฐ ๋์น๋ ๋ถ๋ถ์ด ์์ ๊ฒ ๊ฐ๋ค๋ ์๊ฐ์ด ๋ค์๋ค.
// model/post.js
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
// ๊ฒ์๊ธ : ์ ๋ชฉ, ๋ด์ฉ, ์ฌ์ง, ์
๋ก๋ ๋ ์ง, ์ข์์ ์, ์ข์์ ํ ์ฌ์ฉ์ ๋ชฉ๋ก, ๋๊ธ ๋ชฉ๋ก, ๊ฒ์๊ธ์ ์ด ์ฌ์ฉ์ ๋ฅผ ๊ฐ์ง๊ณ ์๋ค.
const postSchema = new Schema({
title: String,
content: String,
image: String,
publishedDate: String,
likeCount: {
type: Number,
default: 0
},
// ๋๊ธ ๋จ user ์ ๋ณด๋ฅผ Array๋ก ๊ด๋ฆฌํ๋๊ฒ ๋จธ๋ฆฌ๋ก๋ ์ดํด๊ฐ ๊ฐ๋๋ฐ ์ด๋ ๊ฒ ํ์
, default๋ฅผ ์ฃผ๋๊น ์ ๊ธฐํ๋ค..
likeUser: {
type: Array,
default: []
},
comment: {
type: Array,
default: []
},
user: {
// user ์ ๋ณด๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ๊ฐ์ ธ์ด.
_id: mongoose.Types.ObjectId,
username: String
}
});
module.exports = mongoose.model("post", postSchema);
// model/auth.js
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
// ๋ก๊ทธ์ธ์ ์ ์ ์ด๋ฆ๊ณผ ๋น๋ฐ๋ฒํธ๊ฐ ์์ผ๋ฉด ๋๋ค.
const authSchema = new Schema({
username: String,
password: String
});
module.exports = mongoose.model("auth", schema);
๊ฒ์๋ฌผ ์์ฑ
๊ฒ์๋ฌผ ์ ์ฒด ์กฐํ / ๊ฒ์๋ฌผ ํ๋ ์กฐํ
๊ฒ์๋ฌผ ์์
๊ฒ์๋ฌผ ์ญ์
์ ๋ฒ์๋ ์ด๋ฏธ์ง๋ฅผ ์๋ฒ์ ์ ์ฅ์ ํ์์ง๋ง, ์ด๋ฒ์๋ AWS S3์ ์ ๋ก๋๋ฅผ ํ๊ณ ๋ฐ์์๋ค. -> multer-s3 ํจํค์ง ์ฌ์ฉ.
๊ทธ๋ฐ๋ฐ.. ๋ด AWS ๊ณ์ ์ free-tier ๊ธฐ๊ฐ์ด ํ ๋ฌ ์ฐจ์ด๋ก ๋๋์... ๊ทธ๋ฅ ์ง์ผ๋ณด๋ฉด์ ์ฝ๋์ ๋ก์ง์ ์ดํดํ๋ ๋ฐฉํฅ์ผ๋ก ์์ ์ ๋ค์๋๋ฐ, ์๋ง ์๋ฒ ์ผ๊ณ ์ค์ต์ ํ์ผ๋ฉด... ์ค๋ฅ ์ก๋๋ผ ์๊ฐ ๋ด๋ก ๊ฐ์๋ฅผ ๋ค ๋ชป๋ค์์ ๊ฒ ๊ฐ๋ค.
// module/multer.js
// AWS S3 ์ ๋ํ ์ค์ ์ ๋ด๋นํ๋ ๋ชจ๋
const mutler = require("multer");
const multerS3 = require("multer-s3");
const aws = require("aws-sdk");
aws.config.loadFromPath(__dirname + "/../config/s3Info.json"); // AWS ํค๋ฅผ ์ ์ฅํ ํ์ผ s3Info
const s3 = new aws.S3();
// upload๋ฅผ ํ ๋ ์ฌ์ฉํ๋ multer ๋ชจ๋
const upload = multer({
storage: multerS3({
s3: s3,
bucket: 'bucketname',
acl: 'public-read-write',
key: (req, file, cb) => {
cb(null, Date.now() + "." + file.originalname.split(".").pop()); // ํ์ผ ์ด๋ฆ์ ์ ๋ํฌํ์ด๋ฆ.ํ์ฅ์ ํํ๋ก
}
})
});
module.exports = upload;
routes ํด๋ ์์ ์๋ ๊ฒ์๋ ์ ๋ง route์ ๊ดํ ์ฝ๋๋ง ์์ฑํ๊ณ , ๋ก์ง์ Controller๋ก ๋นผ์ ์์ฑํ๋ค. MVC๊ฐ ์๊ฐ๋ฌ๋ค.. ์ด์ ํ๋ ์ฝ๋๋ controller์์ ๋ก์ง์ ๋ด๋นํ๋ ๊ตฌ์กฐ๋ก ๋ฐ๊ฟ๋ณด๋ฉด ์ข์ ๊ฒ ๊ฐ๋ค.
// controller/postCtr.js
// ๊ฒ์๋ฌผ CRUD ๋ก์ง์ ๋ด๋นํ๋ ์ปจํธ๋กค๋ฌ
const Post = require("../model/post");
// Date๋ฅผ 2021-12-28 ํ์์ผ๋ก ๋ฐ๊ฟ์ฃผ๋ ํจ์.
const formatDate = (date) => {
let d = new Date(date);
let month = ("" + (d.getMonth() + 1)).padStart(2, "0");
let day = ("" + d.getDate()).padStart(2, "0");
let year = d.getFullYear();
return [year, month, day].join('-');
}
// ๊ฒ์๋ฌผ ์ปจํธ๋กค๋ฌ ๊ฐ์ฒด
const postCtr = {
// 1. create : upload func
upload: async (req, res) => {
const { title, content } = req.body;
const image = req.file.location; // image ๋ S3์์ ๋ถ๋ฌ์จ๋ค.
const publishedDate = formatDate(new Date());
const post = new Post({
title: title,
content: content,
image: image,
publishedDate: publishedDate,
user: req.userInfo // ํญ์ jwt ํ ํฐ์ ์์ฒญ์ ํฌํจํด์ ๋ณด๋ด๊ธฐ ๋๋ฌธ์ req์ userInfo๊ฐ ์๋ค.
});
try {
await post.save();
res.redirect("/");
} catch(error) {
res.status(500).send("upload error!");
}
},
// 2. read : ๋ฉ์ธ ํ์ด์ง์์ ๊ธ ์ ์ฒด list ์กฐํ ํด์ผํจ.
list : async (req, res) => {
const posts = await Post.find({}); // ์ ์ฒด ๊ฒ์๋ฌผ ๊ฐ์ ธ์ฌ๊ฑฐ๋ผ {}๋ก ์ฐพ๋๋ค.
res.render("index", { postList: posts });
},
// 2. read : ๊ธ ํ๋ํ๋๋ฅผ ์กฐํ
detail: async (req, res) => {
const { id } = req.params;
const post = await Post.findById(id);
res.render("detail", { post : post });
},
// 3. update : update ํ ๋ update ํ์ด์ง์ ๊ธฐ์กด ๊ธ์ ์ ๋ณด๊ฐ ๋์ด์ค๋๋ก
updateLayout: async (req, res) => {
const {id} = req.params;
const post = await Post.findById(id);
res.render("update", { post : post });
},
// ์
๋ฐ์ดํธ ๋ฒํผ ๋๋ฅด๋ฉด ์
๋ฐ์ดํธ ๋จ.
update: async (req, res) => {
try {
const { id } = req.params;
const { title, content } = req.body;
await Post.findByIdAndUpdate(
id,
{ title, content },
{ new: true } // ์
๋ฐ์ดํธ ๋๋ฉด ์๋ก ๋ฐ์์ฌ๊ฑด์ง. ์ํ๋ฉด ๊ธฐ์กด post๋ฅผ ๋ฐ์์ค๊ฒ ๋จ.
);
res.redirect("/");
} catch(error) {
res.status(500).send("update error");
}
},
// 4. delete
delete: async (req, res) => {
try {
const {id} = req.params;
await Post.findByIdAndDelete(id);
res.redirect("/");
} catch(error) {
res.status(500).send("delete error");
}
}
}
module.exports = postCtr;
// routes/posts/index.js
const express = require("express");
const { route } = require("..");
const router = express.Router();
const upload = require("../../module/multer");
const postCtr = require('../../controller/postCtr');
// 1. create
router.get('/upload', checkUser, (req, res) => {
res.render('upload');
});
// 2. read
router.get("/", postCtr.list); // ๊ฒ์๋ฌผ ์ ์ฒด ์กฐํ.
router.get("/:id", postCtr.detail); // ๊ฒ์๋ฌผ ํ๋ ์กฐํ
// 3. update
// web์์ form ํํ๋ก ๋ฐ์ดํฐ๋ฅผ ์ ์กํ๋ฉด get / post ๋๊ฐ์ง ๋ฐ์ ์ธ ์ ์๊ธฐ ๋๋ฌธ์
// update์ PUT์ด ์๋๋ผ POST ๋ฉ์๋๋ฅผ ์ฌ์ฉํ์ฌ ์์ฒญ ๋ณด๋.
router.post('/update:id', postCtr.updateLayout);
router.post('/', upload.single("image"), postCtr.upload);
router.post('/update:id', postCtr.update);
// 4. delete
router.post('/delete/:id', postCtr.delete);
module.exports = router;
์ด์ ์ฌ์ฉํ๋ ์ธ์ ์, ์๋ฒ์์ ์ธ์ ์ ๊ฐ์ง๊ณ , ํด๋ผ์ด์ธํธ๊ฐ ๋ก๊ทธ์ธ ๋์ด์๋์ง ์๋์ง ํ์ธํ๋ค. ๊ทธ๋ฐ๋ฐ ์ธ์ ์ ์ ์ฅ ๋ฐ์ดํฐ๊ฐ ๋ง์์ง๋ฉด ์๋ฒ์ ๋ถํ๊ฐ ๊ฑธ๋ฆฌ๊ธฐ ๋๋ฌธ์ ํด๋ผ์ด์ธํธ๊ฐ ์ฟ ํค๋ฅผ ํตํด ์ ๋ณด๋ฅผ ๊ฐ์ง๊ณ ์๊ฒ ํ๊ธฐ๋ ํ๋ค. ํ์ง๋ง ์ฟ ํค๋ ๋ณด์์ด ์ทจ์ฝํด์ id, pw๋ฅผ ๋ด๋๊ฒ ์๋๋ผ ์๋๋ก๊ทธ์ธ์ ํ ์ ์๋ ์ ๋ณด๋ฅผ ๋ด์๋ฌ์ผ ํ๋ค.
JWT๋ json Web Token์ผ๋ก json ํํ์ ํ ํฐ์ ์๋ฒ๊ฐ ์๋๋ผ ๋ธ๋ผ์ฐ์ (์ฟ ํค)์ ์ ์ฅํด์ ์ธ์ฆํ ์ ์๊ฒ ํ๋ค.
๊ตฌ์กฐ
ํด๋ผ์ด์ธํธ๊ฐ id, pw ๋ฅผ ์๋ฒ์ ๋ณด๋ด๊ณ ์ธ์ฆ์ด ๋์๋ค๋ฉด, ์๋ฒ๋ ์์ ์ ๋น๋ฐํค๋ฅผ ์ด์ฉํด์ JWT ํ ํฐ์ ์ํธํํด์ ๋ณด๋ธ๋ค. ๊ทธ๋ฌ๋ฉด ํด๋ผ์ด์ธํธ๋ JWT๋ฅผ ์ฟ ํค๋ ๋ธ๋ผ์ฐ์ ์ ์ ์ฅํด๋๊ณ , ๋ชจ๋ ์์ฒญ์ JWT ํ ํฐ์ ๊ฐ์ด ๋ณด๋ธ๋ค. ๊ทธ๋ฌ๋ฉด ์๋ฒ๊ฐ ํ ํฐ์ ๋ณตํธํํด๋ณด๊ณ ์ ๋ณด๊ฐ ๋ง์ผ๋ฉด ๊ทธ์ ๋ง๋ ์๋ต์ ํ๋ค.
๋ก๊ทธ์ธ - ํ ํฐ ๋ฐ๊ธ
์ฌ์ฉ์ ํ์ธ - ํ ํฐ ํ์ธ
๋ก๊ทธ์์ - ํ ํฐ ์ญ์
// routes/auth/index.js
const express = require("express");
const router = express.Router();
const authCtr = require('../../controller/authCtr');
// ํ์๊ฐ์
router.get('/register', (req, res) => {
res.render("register");
});
router.post('/register', authCtr.register);
// ๋ก๊ทธ์ธ
router.get('/login', authCtr.login);
// ๋ก๊ทธ์์
router.post("/logout", (req, res) => {
res.clearCookie("access_token");
res.redirect("/");
});
module.exports = router;
// controller/authCtr.js
const bcrypt = require("bcrypt");
const User = require('../model/auth');
const secretKey = require('../config/secretKey.json');
const jwt = require("jsonwebtoken");
const authCtr = {
// ํ์๊ฐ์
register: async (req, res) => {
const { username, password } = req.body;
const exist = await User.findOne({ username: username }); // username ๊ณผ ์ผ์นํ๋ ํญ๋ชฉ์ด ์๋์ง
// user๊ฐ ์์ผ๋ฉด ํ์๊ฐ์
๋ถ๊ฐ๋ฅ
if (exist) {
res.status(504).send("user exists");
return
}
const user = new User({
username: username
});
const hashedPassword = await bcrypt(password, 10); // hash 10๋ฒ
user.password = hashedPassword;
await user.save();
res.redirect('/');
},
// ๋ก๊ทธ์ธ
login : async (req, res) => {
const { username, password } = req.body;
// ๋ก๊ทธ์ธ์ด๋๊น ์ ์ ๋ฅผ ์ฐพ์์์.
const user = await User.findOne({ username : username });
if (!user) {
res.status(500).send("user not found");
return;
}
// ๋๋ === ์ผ๋ก ๋น๊ตํ ์๊ฐ์ ํ๋๋ฐ, compare๋ผ๋ ๋ฉ์๋๊ฐ ์์๋ค. ๊ทผ๋ฐ hash 10๋ฒํ๋๋ฐ ๊ทธ๊ฒ๋ ๋ฐ์์ด ๋๋๊ฒ ์ ๊ธฐํ๋ค.
const valid = await bcrypt.compare(password, user.password);
if (!valid) {
res.status(500).send("password invalid");
return;
}
// ์ฑ๊ณต. JWT ํ ํฐ ๋ฐ๊ธํด์ ๋ณด๋ธ๋ค.
// secretKey๋ config์ ์๋ค. ์ํธํํ ํค ๊ฐ์ด๋ค.
const data = user.toJSON();
delete data.password;
const token = jwt.sign({
_id: data.id,
username: data.username
}, secretKey.key,
{
// ์ค๋ฌด์์๋ 30๋ถ ์ ๋๋ก ์งง๊ฒ ์ค์ผํ์ง๋ง ํ
์คํธ์ฉ์ด๋ ๊ธธ๊ฒ
expiresIn: "7d"
});
res.cookie("access_token", token, {
maxAge: 1000 * 60 * 60 * 24 * 7,
httpOnly: true
});
res.redirect("/");
}
};
์ฌ์ฉ์ ์ ๋ณด๋ CUD์์ ๋ชจ๋ ํ์ธํด์ผ ํ๋ฏ๋ก, middleware ํจ์๋ฅผ ๋ง๋ค์ด์ ์ด์ฉํ๋ค.
// app.js
const jwtMiddleware = require('./module/jwtMiddleware');
// ๋ชจ๋ ๋์์ ํ ๋ ํ ํฐ์ ํ์ธํ๋ค.
app.use(jwtMiddleware);
<!-- navbar.ejs -->
<!-- ๋ก๊ทธ์ธ์ด ๋์ด ์์ผ๋ฉด ๋ฒํผ์ด ๊ธ์ฐ๊ธฐ๋ก ์๋์ด ์์ผ๋ฉด ๋ก๊ทธ์ธ์ผ๋ก ๋ฐ๋๊ฒ-->
<div class="navbar_menu">
<div style="font-weight: bolder;font-size:1.5rem;">
<a style="color:#000000;text-decoration: none;" href="/">SNS</a>
</div>
<div class="auth_wrap">
<% if (isAuthenticated.username) { %>
<button onclick="location.href='/posts/upload'" style="width: 100%; margin-top: 0" class="ui secondary button">
๊ธ์ฐ๊ธฐ
</button>
<form action="/auth/logout", method="POST">
<button type="submit" style="margin-top: 0;" class="ui secondary button">๋ก๊ทธ์์</button>
</form>
<% } else { %>
<button onclick="location.href='/auth/login'" style="width: 100%; margin-top: 0" class="ui secondary button">
๋ก๊ทธ์ธ
</button>
<% } %>
</div>
</div>
// modlue/jwtMiddleware.js
// ์ฌ์ฉ์ ํ์ธ ๊ธฐ๋ฅ
const jwt = require("jsonnwebtoken");
const secretKey = require("../config/secretKey.json");
const jwtMiddlware = async (req, res, next) => {
const token = req.cookies.access_token;
if(!token) {
// isAuthenticated ์ ๋น ๊ฐ์ฒด๋ฅผ ๋๊น (ํ ํฐ์ด ์์ผ๋๊น)
res.locals.isAuthenticated = {};
return next();
}
try {
// ํ ํฐ์ด ์์ผ๋ฉด ๊ฒ์ฆ.
const decoded = jwt.verify(token, secretKey.key);
req.userInfo = {
_id: decoded.id,
username: decoded.username
};
res.locals.isAuthenticated = { username : decoded.username };
return next();
} catch(error) {
res.status(500).send("jwt error");
}
}
์ฌ์ฉ์ ์ ๋ณด๋ฅผ ํ์ธํ ํ์๋ง ๊ธ์ฐ๊ธฐ๋ฅผ ํ ์ ์๊ฒ.
// module/checkUser.js
// posts/index.js ์ ๊ธ์ฐ๊ธฐ, ์์ , ์ญ์ ์ middleware๋ก checkUser ๋ถ์ด๊ธฐ.
const checkUser = (req, res, next) => {
if (!req.userInfo) {
res.status(400).send("user not login!");
return;
}
return next();
}
module.exports = checkUser;
// index.ejs
// ํํธ ๋ฒํผ์ ๋๋ฅด๋ฉด, /posts/like/${id} ๋ก ์์ฒญ์ ๋ณด๋ด๊ณ ,
// ์ฑ๊ณต์ธ ๊ฒฝ์ฐ ๋ฐ์ ์๋ต์ ๊ธฐ๋ฐ์ผ๋ก ํํธ๊ฐ ์ฑ์์ง๊ณ ์์ฑ์์ง๊ฒ.
$(".heart-count").click(function (e) {
const id = $(this).attr("key");
$.ajax({
url: `/posts/like/${id}`,
type: "POST",
cache: false,
dataType: "json",
success: function (data) {
$(`#${id} > span`).text(data.post.likeCount);
if (!data.check) {
$(`#${id}`).addClass("checked");
} else {
$(`#${id}`).removeClass("checked");
}
},
error: function (request, status, error) {
alert(
error
);
},
});
});
// routes/posts/index.js
// ์ข์์
router.post('/like/:id', postCtr.like);
// controller/postCtr.js/postCtr
like: async (req, res) => {
const { id } = req.params;
const post = await Post.findById(id);
// jwt ์์ฑ์ req.userInfo ๋ฅผ ๋ฃ์๊ธฐ ๋๋ฌธ์ ์ฌ์ฉ ๊ฐ๋ฅ.
const check = post.likeUser.some(userId => userId === req.userInfo._id);
if (check) {
post.likeCount -= 1;
const idx = post.likeUser.indexOf(req.userInfo._id);
if (idx > -1) {
post.likeUser.splice(idx, 1);
}
} else {
post.likeCount += 1;
post.likeUser.push(req.userInfo._id);
}
const result = await post.save();
res.status(200).json({
check: check,
post: result
});
}
// index.ejs
// ๋๊ธ ๋ฒํผ์ ๋๋ฅด๋ฉด ๋๊ธ ์ฐฝ์ด ๋ด๋ ค์ค๊ฒ.
$(".comment_button").click(function (e) {
const id = $(this).attr("key");
$(`#comment_wrap_${id}`).slideToggle();
});
// ๋๊ธ์ฐฝ์ ์
๋ ฅํ๊ณ ์ํฐ๋ฅผ ๋๋ฅด๋ฉด /posts/comment/${id}๋ก ์ ๊ทผํ์ฌ
// ์๋ต์ ๋ฐ๊ณ ํด๋น ์ ๋ณด๋ฅผ ํ๋ฉด์ ๋ณด์ฌ์ฃผ๊ฒ ๋๋ค.
$(".comment_input").keydown(function (e) {
if (e.keyCode === 13) {
e.preventDefault();
const id = $(this).attr("key");
const inputCommnet = $(this).val();
$(this).val("");
$.ajax({
url: `/posts/comment/${id}`,
type: "POST",
cache: false,
dataType: "json",
data: {
comment: inputCommnet,
},
success: function (data) {
const comment = data.post.comment;
let comment_body = "";
const arr = comment.reverse();
arr.forEach((e) => {
console.log("EEE");
comment_body += `
<div class="comment_body_item">
<div style="font-weight: bolder;">
${e.user.username}
</div>
<div>
${e.comment}
</div>
</div>
`;
});
$(`#comment_${id}`).html(comment_body);
},
error: function (request, status, error) {
alert(
error
);
},
});
}
});
// routes/posts/index.js
// ๋๊ธ
router.post('comment/:id', checkUser, postCtr.comment);
// controller/postCtr.js
comment: async (req, res) => {
const { id } = req.params;
const post = await Post.findById(id);
const user = req.userInfo;
const { comment } = req.body;
const commentWrap = {
comment: comment,
user: user
};
post.comment.push(commentWrap);
const result = await post.save();
res.status(200).json({post: result});
},
๊ธฐ์กด์ ํ๋ ๋ฐฉ๋ฒ์ผ๋ก๋ ์ค์๊ฐ ์ฑํ ์ ๊ตฌํํ ์ ์๋ค. ๊ธฐ์กด์ ๋ฐฉ์์ ํด๋ผ์ด์ธํธ๊ฐ ์์ฒญ์ ๋ณด๋ด์ผ๋ง ์๋ฒ๊ฐ ์๋ต์ ํด์ฃผ๊ธฐ ๋๋ฌธ! ๋๊ตฐ๊ฐ ์ฑํ ์ ๋ณด๋ด๋ฉด ์๋ฒ๊ฐ ๋ชจ๋ ํด๋ผ์ด์ธํธ์๊ฒ ์ฑํ ๋ด์ฉ์ ์๋ตํด์ผํ๋๋ฐ, ๋ค๋ฅธ ํด๋ผ์ด์ธํธ๊ฐ ์์ฒญ์ ๋ณด๋ด์ง๋ ์์๋๋ฐ ์๋ต? ๋ถ๊ฐ๋ฅ.
-> WebSocket์ด ๋ฑ์ฅํ๋ฉด์ ๊ฐ๋ฅํด์ก๋ค.
socket.io : WebSocket์ ์ฝ๊ฒ ๋ง๋ค ์ ์๊ฒ ๋ง๋ค์ด์ค.
emit, on๋ง ์๋ฉด ์ฝ๊ฒ ์ฑํ ์ ๊ตฌํํ ์ ์๋ค. emit์ผ๋ก ๋ณด๋ด๊ณ , on์ผ๋ก ๋ฐ๊ณ .
// index.ejs
$(() => {
// ์ธ์ฆ๋ฐ์ ์ ๋ณด๋ก ์ด๋ฆ ์ค์ .
const name = "<%= isAuthenticated.username %>";
const socket = io();
// ์ฑํ
ํผ์ ์ ์ถํ์ ๋, chat-msg๋ฅผ emit์ผ๋ก ์๋ฒ์ ๋ณด๋.
$("#chat_form").submit(() => {
socket.emit("chat-msg", name, $(".chat_input").val());
$(".chat_input").val("");
return false;
});
// chat-msg๋ฅผ on์ผ๋ก ๋ค์ ๋ฐ์์ ํ๋ฉด์ ๋ณด์ด๊ฒ ์ฒ๋ฆฌ
socket.on("chat-msg", (name, msg) => {
let chat = `<div class="chat_block">
<span style="font-weight: bolder">${name}</span> :
${msg}
</div>`;
$(".chat_content").append(chat);
});
});
// bin/www
app.io.attach(server);
// app.js
app.io = require("socket.io");
// server์์๋ on์ผ๋ก ๋ฐ๋๋ค.
app.io.on("connection", (socket) => {
socket.on("chat-msg", (user, msg) => {
app.io.emit("chat-msg", user, msg);
});
});
์ค๋์ ๋นจ๋ฆฌ ์์ผ๊ฒ ๋ค.
node๊ฐ ๋ฐฑ์๋ ์ค์ ๊ฐ์ฅ ์ฝ๋ค๊ณ ํ๋๋ฐ, ๊ทธ๋์ ๊ทธ๋ฐ์ง ๊ฒ๋๋ ๊ฒ ๋ณด๋ค๋ ์ ๋ง ํ ๋งํ๋ค. ๋ฌผ๋ก ํผ์ ํ๋ผ๊ณ ํ๋ฉด..? ํ ์ ์์์ง๋ ์ ๋ชจ๋ฅด๊ฒ ๋ค.
์ด๋ค ๊ฑธ ์๋ฒ๋ก ๋ณด๋ด๊ณ ์ด๋ค ๊ฑธ ๋ฐ์ ๊ฒ์ด๋ผ req res์ ๋ค์ด๊ฐ๋ ์ ๋ณด๊ฐ ๋ฌด์์ธ์ง ๋ฐ๋ก๋ฐ๋ก ํ์
ํ๋ ๊ฒ๋ ๋ฅ์ํด์ ธ์ผ ๊ฐ๋ฅํ ๊ฒ ๊ฐ๋ค. ํ ํฐ ์์ฑํ ๋ req.userInfo
๋ฃ์ด๋๊ณ ๋์ค์ ์ด๊ฑธ ์ด๋์ ๋ฃ์๋๋ผ.....??? ํ๋ฉด์ ํท๊ฐ๋ ธ๋ค.
๋คํธ์ํฌ ์ฐ๊ฒฐ ๋ถ๋ถ์ด ๊ฐ๋ ์ ์์ค๊ณ swift์ ๊ฒฝ์ฐ๋ ๋ด ์ํฉ์ ๋ง๋ ์์ ์ฝ๋๋ ์ฐพ๊ธฐ๊ฐ ํ๋ค์๋๋ฐ, ๋ฐฑ์๋๋ฅผ ๋ง๋ค๋ฉด์ ์๋ต์ ๋ง๋ค์ด๋ณด๋๊น ์ข ๊ฐ์ด ์จ๋ค. ๋ฉ์ฌ ๊ต์ก๊ณผ์ js์์ ์ฝ๋ฐฑํจ์, Promise, async await, closure์ ๋ํด์ ์ ๋๋ก ๋ค๋ฃจ๊ณ , ์ฌ๊ธฐ์ ์ฌ์ฉ๋ ํด๋ณด๋๊น ์ด์ ๋ด ์ฑ์ด ์ ์๋ฒ์ ์๋ต๋ ๋ฐ๊ธฐ ์ ์ ํผ์ ์คํ์ด ๋ผ์ ์ค๋ฅ๊ฐ ๊ณ์ ๋ฌ๋์ง ์๊ฒ ๋ค.. async await๋ฅผ ์ ์ฌ์ฉํด๋ณด์.
์ถ์ฒ
์ฝ๋๋ผ์ด์ธ ์ผ๋จ ๋ง๋๋ node.js - ์ด๋ํ ๊ฐ์ฌ๋
์ฐ์ค์ ๋ ธ๋ ๊ณต๋ถ ์งฑ์ด์ฌํ ํ์ จ๋ค์!! ๋ฐ์ฑํ๊ตฌ ์ ๋ ์์ ๋ค์ผ๋ฌ ๊ฐ๋๋ค,,