백엔드 노드 서버 구축하기
버전이 다르기 때문에 소스가 강좌와 다를 수 있다.
버전
next: 13.0.4
antd: 5.0.1
소스 : https://github.dev/braverokmc79/node-bird-sns
46. 회원가입 구현하기
강의 :
백엔드
app.js
~ const express = require('express'); const postRouter = require('./routes/posts'); const userRouter = require('./routes/user'); const db = require('./models'); const app = express(); db.sequelize.sync() .then(() => { console.log('db 연결 성공'); }) .catch(console.error); app.use(express.json()); app.use(express.urlencoded({ extended: true })); ~ app.use('/post', postRouter); app.use('/user', userRouter);
비밀번호 암호화 위해
$ npm i bcrypt
routes/user.js
const express = require('express'); const { User } = require('../models'); const bcrypt = require('bcrypt'); const router = express.Router(); router.get('/', (req, res) => { // User.create console.log(" get 백엔드 : ", req.body); res.json({ success: true }) }); router.post('/', async (req, res, next) => { try { console.log(" 백엔드 : ", req.body); const exUser = await User.findOne({ where: { email: req.body.email } }); if (exUser) { return res.status(403).send('이미 사용중인 아이디입니다.'); } const hashedPassword = await bcrypt.hash(req.body.password, 12); await User.create({ email: req.body.email, nickname: req.body.nickname, password: hashedPassword }); res.status(201).send('ok'); } catch (error) { console.error(" 회원 가입 error : ", error); next(error); //status 500 } }); module.exports = router;
47. CORS 문제 해결하기
강의 :
백엔드 서버에 cors 설치
npm i cors
app.js
const express = require('express'); const postRouter = require('./routes/posts'); const userRouter = require('./routes/user'); const cors = require('cors'); const db = require('./models'); const app = express(); db.sequelize.sync() .then(() => { console.log('db 연결 성공'); }) .catch(console.error); app.use(cors({ //origin: 'https://nodebird.com' origin: true, // orign: true 로 설정해두면 * 대신 보낸 곳의 주소가 자동으로 들어가 편리합니다. credentials: false })); app.use(express.json()); app.use(express.urlencoded({ extended: true })); ~
CORS?
CORS(Cross Origin Resource Sharing) 는 추가적인 HTTP 헤더를 사용해서
한 출처에서 실행 중인 웹 애플리케이션이 다른 출처의 자원에 접근할 수 있는 권한을 관리하는 체제입니다.
즉 위와 같이 domain-a.com 에서 같은 주소의 domain-a.com 에 접근하여 자원을 요청할때는 문제가 발생하지 않지만,
domain-b.com 에 요청할 경우 도메인이 다르기 때문에 보안상의 이유로 제한됩니다.
만약 서버에서 올바른 CORS 헤더를 포함한 응답을 반환하지 않으면 위와 같은 오류가 발생하게 됩니다.
위 예시에서는 자원을 가지고 있는 서버단의 도메인인 http://127.0.0.1:3000 과 자원을 요청한 http://localhost:8080 의 출처가 다르기 때문에 발생한 오류입니다.
Node.js에서 CORS 설정
CORS 패키지 설치
우선 CORS 미들웨어를 사용하기 위해 패키지를 설치합니다.
$npm i cors
모든 CORS Request 허용하기
모든 요청을 허용할 경우 다음과 같이 간단하게 미들웨어를 불러와서 추가해주는 것으로 해결할 수 있습니다.
app.js
const express = require("express"); const cors = require("cors"); const app = express(); app.use(cors()); // CORS 미들웨어 등록 // ...
Whitelist로 특정 주소만 허용하기
모든 CORS 요청을 허용해주는 것이 때로는 보안상의 문제로 이어질 수 있습니다.
만약 특정 호스트만 CORS 요청을 허용해주고 싶다면 다음과 같이 whitelist 를 추가해서 검증하는 방법이 있습니다.
요청을 허용할 주소를 담은 whitelist 를 생성해주고 요청 HTTP 헤더의 Origin 속성을 확인해서
일치하는 항목이 있을 경우 허용해주는 방식입니다.
app.js
const express = require("express"); const cors = require("cors"); const app = express(); const whitelist = ["http://localhost:8080"]; const corsOptions = { origin: function (origin, callback) { if (whitelist.indexOf(origin) !== -1) { callback(null, true); } else { callback(new Error("Not Allowed Origin!")); } }, }; app.use(cors(corsOptions)); // 옵션을 추가한 CORS 미들웨어 추가 // ...
참고 자료
- https://expressjs.com/en/resources/middleware/cors.html
- https://developer.mozilla.org/ko/docs/Web/HTTP/CORS
48. 패스포트로 로그인하기.
강의 :
라이브러리 설치
$ npm i passport passport-local $ npm i express-session
app.js
const express = require('express'); const postRouter = require('./routes/posts'); const userRouter = require('./routes/user'); const cors = require('cors'); const db = require('./models'); const passportConfig = require('./passport'); const app = express(); db.sequelize.sync() .then(() => { console.log('db 연결 성공'); }) .catch(console.error); passportConfig(); ~
passport/index.js
const passport = require('passport'); const local = require('./local'); module.exports = () => { passport.serializeUser(() => { }); passport.deserializeUser(() => { }); local(); }
passport/local.js
const passport = require('passport'); const { Strategy: LocalStrategey } = require('passport-local'); const bcrypt = require('bcrypt'); const { User } = require('../models'); module.exports = () => { passport.use(new LocalStrategey({ usernameField: 'email', passwordField: 'password', }, async (email, password, done) => { try { const user = await User.findOne({ where: { email } }); if (!user) { return done(null, false, { reason: '존재하지 않는 사용자입니다.' }) } const result = await bcrypt.compare(password, user.password); if (!result) { return done(null, false, { reason: '비밀번호가 틀렸습니다.' }); } return done(null, user); } catch (error) { console.error(" 로그인 에러 : ", error); return done(error); } })); }
routes/user.js
const express = require('express'); const { User } = require('../models'); const bcrypt = require('bcrypt'); const passport = require('passport'); const router = express.Router(); //passport.authenticate 미들웨어는 (req, res, next) 사용할수 없는 미들웨어인데 다음과 미들웨어 확장 같은 설정으로 사용 //POST /user/login router.post('/login', (req, res, next) => { console.log("로그인 ", req.body); passport.authenticate('local', (err, user, info) => { if (err) { console.error(err); console.error("1.로그인 에러 ", err); next(err); } //현재 info 가 존재하면 클라이언트 에러 //info 예 => { reason: '존재하지 않는 사용자입니다.' } { reason: '비밀번호가 틀렸습니다.' } if (info) { //401 허가되지 않음 403 금지 return res.status(401).send(info.reason); } return req.login(user, async (loginErr) => { if (loginErr) { console.error("2.로그인 에러 ", loginErr); return next(loginErr); } return res.status(200).json(user) }); })(req, res, next); }); ~
49. 쿠키/세션과 전체 로그인 흐름.
강의 :
라이브러리 추가
$ npm i cookie-parser $ npm i dotenv
app.js 다음 4가지 추가
app.use(cookieParser); app.use(session()); app.use(passport.initialize()); app.use(passport.session());
app.js => routes/user.js => passport/index.js 에서 local 함수 실행 = > passport/local.js
app.js =>
const express = require('express'); const postRouter = require('./routes/posts'); const userRouter = require('./routes/user'); const cors = require('cors'); const db = require('./models'); const passportConfig = require('./passport'); const passport = require('passport'); const session = require("express-session"); const cookieParser = require('cookie-parser'); const dotenv = require('dotenv'); dotenv.config(); const app = express(); db.sequelize.sync() .then(() => { console.log('db 연결 성공'); }) .catch(console.error); app.use(cors({ //origin: 'https://nodebird.com' origin: true, // orign: true 로 설정해두면 * 대신 보낸 곳의 주소가 자동으로 들어가 편리합니다. credentials: false })); app.use(express.json()); app.use(express.urlencoded({ extended: true })); app.use(cookieParser()); app.use(session({ secret: process.env.COOKIE_SECRET, resave: false, saveUninitialized: false })); app.use(passport.initialize()); //패스포트 초기화 app.use(passport.session()); passportConfig(); app.get('/', (req, res) => { res.send('hello express'); }); app.get('/api', (req, res) => { res.send('hello api'); }); app.get('/api/posts', (req, res) => { res.json([ { id: 1, content: 'hello1' }, { id: 2, content: 'hello2' }, { id: 3, content: 'hello3' } ]) }); app.use('/post', postRouter); app.use('/user', userRouter); app.listen(3065, () => { console.log("서버 실행 중"); });
routes/user.js
const express = require('express'); const { User } = require('../models'); const bcrypt = require('bcrypt'); const passport = require('passport'); const router = express.Router(); //passport.authenticate 미들웨어는 (req, res, next) 사용할수 없는 미들웨어인데 다음과 미들웨어 확장 같은 설정으로 사용 //POST /user/login router.post('/login', (req, res, next) => { console.log("로그인 ", req.body); passport.authenticate('local', (err, user, info) => { if (err) { console.error(err); console.error("1.로그인 에러 ", err); next(err); } //현재 info 가 존재하면 클라이언트 에러 //info 예 => { reason: '존재하지 않는 사용자입니다.' } { reason: '비밀번호가 틀렸습니다.' } if (info) { //401 허가되지 않음 403 금지 return res.status(401).send(info.reason); } console.log("3 passport .req.login 실행 : ", user); return req.login(user, async (loginErr) => { console.log("로그인 처리 "); if (loginErr) { console.error("2.로그인 에러 ", loginErr); return next(loginErr); } console.log("로그인 성공 : ", user); return res.status(200).json(user) }); })(req, res, next); }); //로그아웃 router.post('/logout', (req, res, next) => { req.logout(function (err) { if (err) { return next(err); } req.session.destroy(); res.send('ok') }); }); ~
passport/index.js
const passport = require('passport'); const local = require('./local'); const { User } = require('../models'); module.exports = () => { passport.serializeUser((user, done) => { //메모리에 많은 양의 데이터를 저장하면 메모리 낭비가 심하므로 user id 만 저장 한다. done(null, user.id); }); //user id 를 통해 user 정보를 가져온다. passport.deserializeUser(async (id, done) => { try { const user = await User.findOne({ where: { id } }) done(null, user); //req.user 저장 } catch (error) { console.error(" passport.deserializeUser error : ", error); done(error); } }); local(); }
passport/local.js
const passport = require('passport'); const { Strategy: LocalStrategey } = require('passport-local'); const bcrypt = require('bcrypt'); const { User } = require('../models'); module.exports = () => { console.log(" passport local.js module.exports "); passport.use(new LocalStrategey({ usernameField: 'email', passwordField: 'password', }, async (email, password, done) => { try { const user = await User.findOne({ where: { email } }); if (!user) { return done(null, false, { reason: '존재하지 않는 사용자입니다.' }) } const result = await bcrypt.compare(password, user.password); if (!result) { return done(null, false, { reason: '비밀번호가 틀렸습니다.' }); } return done(null, user); } catch (error) { console.error(" 로그인 에러 : ", error); return done(error); } })); }
dotenv 설정
.env
COOKIE_SECRET=1123@2312dajfj23rj2po4$#%@# DB_PASSWORD=1234
config/config.js
const dotenv = require('dotenv'); dotenv.config(); module.exports = { "development": { "username": "react-nodebird", "password": process.env.DB_PASSWORD, "database": "react_nodebird", "host": "127.0.0.1", "post": "3306", "dialect": "mysql" }, "test": { "username": "react-nodebird", "password": process.env.DB_PASSWORD, "database": "react_nodebird", "host": "127.0.0.1", "post": "3306", "dialect": "mysql" }, "production": { "username": "react-nodebird", "password": process.env.DB_PASSWORD, "database": "react_nodebird", "host": "127.0.0.1", "post": "3306", "dialect": "mysql" } }
50. 로그인 문제 해결하기
강의 :
로그인시 유저정보 뿐만 아니라 Post 및 Followers 및 Followings 데이터를 가져오는 것때문에 오류
routes/user.js
const express = require('express'); const { User, Post } = require('../models'); const bcrypt = require('bcrypt'); const passport = require('passport'); const router = express.Router(); //passport.authenticate 미들웨어는 (req, res, next) 사용할수 없는 미들웨어인데 다음과 미들웨어 확장 같은 설정으로 사용 //POST /user/login router.post('/login', (req, res, next) => { passport.authenticate('local', (err, user, info) => { if (err) { console.error(err); console.error("1.로그인 에러 ", err); next(err); } //현재 info 가 존재하면 클라이언트 에러 메시지 반환처리 //info 예 => { reason: '존재하지 않는 사용자입니다.' } { reason: '비밀번호가 틀렸습니다.' } if (info) { //401 허가되지 않음 403 금지 return res.status(401).send(info.reason); } return req.login(user, async (loginErr) => { if (loginErr) { return next(loginErr); } const fullUserWithoutPassword = await User.findOne({ where: { id: user.id }, //원하는 정보만 attributes: ['id', 'nickname', 'email'], attributes: { exclude: ['password'] }, include: [{ model: Post }, { model: User, as: "Followers" }, { model: User, as: "Followings" } ] }) return res.status(200).json(fullUserWithoutPassword) }); })(req, res, next); }); //로그아웃 router.post('/logout', (req, res, next) => { req.logout(function (err) { if (err) { return next(err); } req.session.destroy(); res.send('ok') }); }); router.post('/', async (req, res, next) => { try { console.log(" 백엔드 : ", req.body); const exUser = await User.findOne({ where: { email: req.body.email } }); if (exUser) { return res.status(403).send('이미 사용중인 아이디 입니다.'); } const hashedPassword = await bcrypt.hash(req.body.password, 12); await User.create({ email: req.body.email, nickname: req.body.nickname, password: hashedPassword }); //res.setHeader('Access-Control-Allow-Origin', 'http://localhost:3060'); //특정서버 // res.setHeader('Access-Control-Allow-Origin', '*'); //모든서버 res.status(201).send('ok'); } catch (error) { console.error(" 회원 가입 error : ", error); next(error); //status 500 } }); module.exports = router;
프론트 엔드 nextjs 에서 다음과 같이 처리
components/LoginForm.js
import React, { useCallback , useEffect} from 'react'; import { Form, Input, Button } from 'antd'; import styled from 'styled-components'; import Link from 'next/link'; import useInput from '../hooks/useInput'; import { useDispatch, useSelector } from 'react-redux'; import { loginRequestAction } from './../reducers/user'; const ButtonWrapper = styled.div` margin-top:10px `; const FormWrapper = styled(Form)` margin-top: 5px; padding:10px; `; const LoginForm = () => { const dispatch = useDispatch(); const { logInLoading, logInError } = useSelector((state) => state.user); const [email, onChangeEmail] = useInput(''); const [password, onChangePassword] = useInput(''); useEffect(() => { if(logInError){ alert(logInError); } }, [logInError]); ~
뒤로가기 못하게 Router.replace('/');
Router.push("/"); => Router.replace("/");
pages/signup.js
~ const SignUp = () => { const dispatch = useDispatch(); const { signUpLoading, signUpDone, signUpError, me } = useSelector((state) => state.user); const { schema } = useSimpleValidation(); const [joinState, setJoinState] = useState(true); useEffect(() => { if (me && me.id) { Router.replace("/"); } }, [me && me.id]); ~
51. 미들웨어로 라우터 검사하기
강의 :
로그인 했는지 안했는지 검사하는 미들웨어 만들기
routes/middlewares.js
exports.isLoggedIn = (req, res, next) => { // 패스포트에서 isAuthenticated 를 제공한다 if (req.isAuthenticated()) { next(); } else { res.status(401).send('로그인이 필요합니다.'); } } exports.isNotLoggedIn = (req, res, next) => { if (!req.isAuthenticated()) { next(); } else { res.status(401).send('로그인하지 않은 사용자만 접근 가능합니다.'); } }
로그인 유무 처리 미들웨어 적용
router.post('/login', isNotLoggedIn, (req, res, next) => { ~ //로그아웃 router.post('/logout', isLoggedIn, (req, res, next) => { ~
routes/user.js
const express = require('express'); const { User, Post } = require('../models'); const bcrypt = require('bcrypt'); const passport = require('passport'); const router = express.Router(); const { isLoggedIn, isNotLoggedIn } = require('./middlewares'); //passport.authenticate 미들웨어는 (req, res, next) 사용할수 없는 미들웨어인데 다음과 미들웨어 확장 같은 설정으로 사용 //POST /user/login router.post('/login', isNotLoggedIn, (req, res, next) => { passport.authenticate('local', (err, user, info) => { if (err) { console.error(err); console.error("1.로그인 에러 ", err); next(err); } //현재 info 가 존재하면 클라이언트 에러 메시지 반환처리 //info 예 => { reason: '존재하지 않는 사용자입니다.' } { reason: '비밀번호가 틀렸습니다.' } if (info) { //401 허가되지 않음 403 금지 return res.status(401).send(info.reason); } return req.login(user, async (loginErr) => { if (loginErr) { return next(loginErr); } const fullUserWithoutPassword = await User.findOne({ where: { id: user.id }, //원하는 정보만 attributes: ['id', 'nickname', 'email'], attributes: { exclude: ['password'] }, include: [{ model: Post }, { model: User, as: "Followers" }, { model: User, as: "Followings" } ] }) return res.status(200).json(fullUserWithoutPassword) }); })(req, res, next); }); //로그아웃 router.post('/logout', isLoggedIn, (req, res, next) => { req.logout(function (err) { if (err) { return next(err); } req.session.destroy(); res.send('ok') }); }); router.post('/', isNotLoggedIn, async (req, res, next) => { try { console.log(" 백엔드 : ", req.body); const exUser = await User.findOne({ where: { email: req.body.email } }); if (exUser) { return res.status(403).send('이미 사용중인 아이디 입니다.'); } const hashedPassword = await bcrypt.hash(req.body.password, 12); await User.create({ email: req.body.email, nickname: req.body.nickname, password: hashedPassword }); //res.setHeader('Access-Control-Allow-Origin', 'http://localhost:3060'); //특정서버 // res.setHeader('Access-Control-Allow-Origin', '*'); //모든서버 res.status(201).send('ok'); } catch (error) { console.error(" 회원 가입 error : ", error); next(error); //status 500 } }); module.exports = router;
52. 게시글, 댓글 작성하기
강의 :
백엔드
routes/posts.js
const express = require('express'); const { Post } = require('../models'); const { isLoggedIn, isNotLoggedIn } = require('./middlewares'); const router = express.Router(); //** passport 특성상 로그인 하면, 라우터 접근시 항상 deserializeUser 실행해서 req.user 를 만든다. req.user.id로 접근해서 정보를 가져올 수 있다. //POST /post router.post('/', isLoggedIn, async (req, res, next) => { try { const post = await Post.create({ content: req.body.content, UserId: req.user.id }); res.status(201).json(post); } catch (error) { console.error(" Post 에러 : ", error); next(error); } }); //POST 댓글 /post router.post('/:postId/comment', isLoggedIn, async (req, res, next) => { //POST /post/1/comment try { const post = await Post.findOne({ where: { id: req.params.postId } }); if (!post) { return res.status(403).send("존재하지 않는 게시글입니다."); } const comment = await Post.create({ content: req.body.content, PostId: req.params.postId, UserId: req.user.id }); res.status(201).json(comment); } catch (error) { console.error(" comment 에러 : ", error); next(error); } }); //DELETE /post router.delete('/', (req, res) => { res.json({ id: 1 }) }); module.exports = router;
프론트엔드
front/reducers/post.js
~ //글작성 case ADD_POST_REQUEST: draft.addPostLoading = true; draft.addPostDone = false; draft.addPostError = null; break; case ADD_POST_SUCCESS: draft.addPostLoading = false; draft.addPostDone = true; draft.mainPosts.unshift(action.data); break; case ADD_POST_FAILURE: draft.addPostLoading = false; draft.addPostError = action.error; break; ~
front/saga/post.js
~ //3-1. 글작성 function addPostAPI(data) { return axios.post('/post', { content: data }); } //3-2. function* addPost(action) { try { const result = yield call(addPostAPI, action.data); console.log("2. 게시글 등록 후 반환 : ", result); yield put({ type: ADD_POST_SUCCESS, data: result.data }); yield put({ type: ADD_POST_TO_ME, data: result.data.id }) } catch (err) { yield put({ type: ADD_POST_FAILURE, error: err.response.data }); } } //댓글 function addCommentAPI(data) { return axios.Comment(`/post/${data.postId}/comment`, data); //POST post/1/comment } function* addComment(action) { try { const result = yield call(addCommentAPI, action.data); yield put({ type: ADD_COMMENT_SUCCESS, data: result.data }); } catch (err) { yield put({ type: ADD_COMMENT_FAILURE, error: err.response.data }); } } function* watchAddComment() { yield takeLatest(ADD_COMMENT_REQUEST, addComment); }
53. credentials로 쿠키 공유하기
강의 :
도메인 URL이 다르면 쿠키전달도 안된다.
cros 처리는 proxy 를 이용한 방법
백엔드에서 다음과 같이 credentials 에서 true 처리를 하여 쿠키 공유
app.js
app.use(cors({ //origin: 'https://nodebird.com' origin: 'http://localhost:3060', // orign: true 로 설정해두면 * 대신 보낸 곳의 주소가 자동으로 들어가 편리합니다. credentials: true }));
origin : true 하면 로그인 오류로 안된다.
프론트엔드에서 다음과 같이
axios.defaults.withCredentials = true;
saga/index.js
import { all, fork } from 'redux-saga/effects'; import axios from 'axios'; import postSaga from './post'; import userSaga from './user'; axios.defaults.baseURL = 'http://localhost:3065'; axios.defaults.withCredentials = true; export default function* rootSaga() { yield all([ fork(postSaga), fork(userSaga), ]); }
백엔드
routes/posts.js
const express = require('express'); const { Post, User, Image, Comment } = require('../models'); const { isLoggedIn, isNotLoggedIn } = require('./middlewares'); const router = express.Router(); //** passport 특성상 로그인 하면, 라우터 접근시 항상 deserializeUser 실행해서 req.user 를 만든다. req.user.id로 접근해서 정보를 가져올 수 있다. //POST /post router.post('/', isLoggedIn, async (req, res, next) => { try { const post = await Post.create({ content: req.body.content, UserId: req.user.id }); const fullPost = await Post.findOne({ where: { id: post.id }, include: [{ model: Image, }, { model: Comment }, { model: User, } ] }) res.status(201).json(fullPost); } catch (error) { console.error(" Post 에러 : ", error); next(error); } }); ~
54. 내 로그인 정보 매번 불러오기
강의:
백엔드
routes/user.js
const express = require('express'); const { User, Post } = require('../models'); const bcrypt = require('bcrypt'); const passport = require('passport'); const router = express.Router(); const { isLoggedIn, isNotLoggedIn } = require('./middlewares'); //브라우저에서 새로고침 할때마다 요청처리 된다. router.get('/', async (req, res, next) => { try { if (req.user) { const fullUserWithoutPassword = await User.findOne({ where: { id: req.user.id }, attributes: { exclude: ['password'] }, include: [{ model: Post, attributes: ['id'], }, { model: User, as: "Followers", attributes: ['id'], }, { model: User, as: "Followings", attributes: ['id'], } ] }) res.status(200).json(fullUserWithoutPassword); } else { res.status(200).json(null); } } catch (error) { console.error("/ 쿠키 정보 가져오기 에러 : ", error); next(error); } }); ~
프론트엔드
pages/index.js
import React, { useEffect, useCallback } from 'react'; import AppLayout from './../components/AppLayout'; import { useSelector, useDispatch } from 'react-redux'; import PostCard from './../components/PostCard'; import PostForm from './../components/PostForm'; import { LOAD_MY_INFO_REQUEST } from './../reducers/user'; import { LOAD_POSTS_REQUEST } from './../reducers/post'; const Index = () => { const dispatch = useDispatch(); const { me } = useSelector((state) => state.user); const { mainPosts, hasMorePosts, loadPostsLoading } = useSelector((state) => state.post); useEffect(() => { dispatch({ type: LOAD_MY_INFO_REQUEST }); dispatch({ type: LOAD_POSTS_REQUEST }); }, []); ~
reducers/user.js
import produce from "immer"; export const initialState = { ~ loadMyInfoLoading: false, //브라우저 새로고침시 유저정보 가져오기 loadMyInfoDone: false, loadMyInfoError: null, me: null, signUpdata: {}, loginData: {} } export const LOAD_MY_INFO_REQUEST = "LOAD_MY_INFO_REQUEST"; export const LOAD_MY_INFO_SUCCESS = "LOAD_MY_INFO_SUCCESS"; export const LOAD_MY_INFO_FAILURE = "LOAD_MY_INFO_FAILURE"; ~ const reducer = (state = initialState, action) => produce(state, (draft) => { switch (action.type) { //브라우저 새로고침시 유저정보 가져오기 case LOAD_MY_INFO_REQUEST: draft.loadMyInfoLoading = true; draft.loadMyInfoDone = false; draft.loadMyInfoError = null; break; case LOAD_MY_INFO_SUCCESS: draft.loadMyInfoLoading = false; draft.loadMyInfoDone = true; draft.me=action.data break; case LOAD_MY_INFO_FAILURE: draft.loadMyInfoLoading = false; draft.loadMyInfoError = action.error; break; ~
saga/user.js
import { all, fork, put, takeLatest, delay, call, throttle } from 'redux-saga/effects'; import axios from 'axios'; import { LOG_IN_REQUEST, LOG_IN_SUCCESS, LOG_IN_FAILURE, LOG_OUT_REQUEST, LOG_OUT_SUCCESS, LOG_OUT_FAILURE, SIGN_UP_REQUEST, SIGN_UP_SUCCESS, SIGN_UP_FAILURE, FOLLOW_REQUEST, FOLLOW_SUCCESS, FOLLOW_FAILURE, UNFOLLOW_REQUEST, UNFOLLOW_SUCCESS, UNFOLLOW_FAILURE, LOAD_MY_INFO_REQUEST, LOAD_MY_INFO_SUCCESS, LOAD_MY_INFO_FAILURE } from '../reducers/user'; //브라우저 새로고침시 유저정보 가져오기 function loadMyInfoAPI() { return axios.get('/user'); } function* loadMyInfo(action) { try { const result = yield call(loadMyInfoAPI) yield put({ type: LOAD_MY_INFO_SUCCESS, data: result.data }); } catch (err) { yield put({ type: LOAD_MY_INFO_FAILURE, error: err.response.data }); } } function* watchLoadMyInfo() { yield takeLatest(LOAD_MY_INFO_REQUEST, loadMyInfo); } ~ //all 하면 한방에 배열로 적은 함수들이 실행처리 된다. //fork , call 로 실행한다. all 은 fork 나 call 을 동시에 실행시키도록 한다. //call 은 동기 함수 호출 //fork 는 비동기 함수 호출 export default function* userSaga() { yield all([ fork(watchLogIn), fork(watchLogOut), fork(watchFollow), fork(watchUnFollow), fork(watchSignUp), fork(watchLoadMyInfo), ]) }
댓글 ( 4)
댓글 남기기