인프런 커뮤니티 질문&답변
user router가 실행되지 않는 문제 질문드리겠습니다.
해결된 질문
작성
·
397
0
아래와 같이 saga도 정상적으로 동작하며, 회원가입 기능, DB에 user 정보 저장, 중복ID체크 오류 모두 정상적으로 동작합니다.
.png)


.png)
근데 network탭을 확인해보니 아래와 같이 user router가 실행되지 않습니다.
또한 cors문제도 해결했는데 Resopnse Headers탭에는 Access-Control-Allow-Origin이 적용되지 않아 질문드립니다.


참고할 수 있는 코드 첨부하겠습니다.
바쁘시겠지만 답변해주시면 정말 감사하겠습니다.
<참고 코드>
signupform
import React, { useCallback, useEffect } from 'react';
import { Button, Checkbox, Form, Input, message } from 'antd';
import { useSelector, useDispatch } from 'react-redux';
import Router from 'next/router';
import { formItemLayout, tailFormItemLayout } from './styles';
import { signupRequestAction } from '../../reducers/user';
const SignupForm = () => {
const { signUpLoading, signUpDone, signUpError } = useSelector((state => state.user));
const dispatch = useDispatch();
const [form] = Form.useForm();
useEffect(() => {
if (signUpDone) {
Router.push('/');
message.success('정상적으로 회원가입이 완료됬습니다.');
}
}, [signUpDone]);
useEffect(() => {
if (signUpError) {
message.error(signUpError);
}
}, [signUpError]);
const onSubmitForm = useCallback((value) => {
console.log(value);
dispatch(signupRequestAction(value));
}, []);
return (
<section>
<Form
{...formItemLayout}
form={form}
name="signup"
onFinish={onSubmitForm}
scrollToFirstError
>
<Form.Item
name="email"
label="E-MAIL"
rules={[
{
type: 'email',
message: 'E-mail형식이 올바르지 않습니다.',
},
{
required: true,
message: 'E-mail을 입력하세요.',
},
]}
>
<Input />
</Form.Item>
<Form.Item
name="password"
label="Password"
rules={[
{
required: true,
message: '비밀번호를 입력하세요.',
},
]}
hasFeedback
>
<Input.Password />
</Form.Item>
<Form.Item
name="confirm-password"
label="Confirm Password"
dependencies={['password']}
hasFeedback
rules={[
{
required: true,
message: '비밀번호를 입력하세요.',
},
({ getFieldValue }) => ({
validator(_, value) {
if (!value || getFieldValue('password') === value) {
return Promise.resolve();
}
return Promise.reject(new Error('비밀번호가 일치하지 않습니다.'));
},
}),
]}
>
<Input.Password />
</Form.Item>
<Form.Item
name="nickname"
label="Nickname"
rules={[
{
type: 'text',
},
{
required: true,
message: '닉네임을 입력하세요.',
},
]}
>
<Input />
</Form.Item>
<Form.Item
name="agreement"
valuePropName="checked"
rules={[
{
validator: (_, value) =>
value ? Promise.resolve() : Promise.reject(new Error('약관에 동의해 주세요.')),
},
]}
{...tailFormItemLayout}
>
<Checkbox>
이용약관에 모두 동의합니다.
</Checkbox>
</Form.Item>
<Form.Item {...tailFormItemLayout}>
<Button type="primary" htmlType="submit" loading={signUpLoading} >회원가입</Button>
</Form.Item>
</Form>
</section>
);
};
export default SignupForm;
reducers/user.js
import produce from 'immer';
import { dummyPost } from './post';
export const initialState = {
me: null,
signUpData: {},
loginData: {},
logInLoading: false,
logInDone: false,
logInError: null,
logOutLoading: false,
logOutDone: false,
logOutError: null,
signUpLoading: false,
signUpDone: false,
signUpError: null,
nicknameEditLoading: false,
nicknameEditDone: false,
nicknameEditError: null,
};
const dummyUser = (data) => ({
...data, // email, password
nickname: 'Mirrer',
id: 2,
Posts: [],
Scrap: [],
Board: [],
});
export const LOG_IN_REQUEST = 'LOG_IN_REQUEST';
export const LOG_IN_SUCCESS = 'LOG_IN_SUCCESS';
export const LOG_IN_FAILURE = 'LOG_IN_FAILURE';
export const LOG_OUT_REQUEST = 'LOG_OUT_REQUEST';
export const LOG_OUT_SUCCESS = 'LOG_OUT_SUCCESS';
export const LOG_OUT_FAILURE = 'LOG_OUT_FAILURE';
export const SIGN_UP_REQUEST = 'SIGN_UP_REQUEST';
export const SIGN_UP_SUCCESS = 'SIGN_UP_SUCCESS';
export const SIGN_UP_FAILURE = 'SIGN_UP_FAILURE';
export const NICKNAME_EDIT_REQUEST = 'NICKNAME_EDIT_REQUEST';
export const NICKNAME_EDIT_SUCCESS = 'NICKNAME_EDIT_SUCCESS';
export const NICKNAME_EDIT_FAILURE = 'NICKNAME_EDIT_FAILURE';
export const BOARD_ADD_POST_TO_ME = 'BOARD_ADD_POST_TO_ME';
export const BOARD_REMOVE_POST_OF_ME = 'BOARD_REMOVE_POST_OF_ME';
export const SCRAP_ADD_POST_TO_ME = 'SCRAP_ADD_POST_TO_ME';
export const SCRAP_REMOVE_POST_OF_ME = 'SCRAP_REMOVE_POST_OF_ME';
export const loginRequestAction = (data) => {
return {
type: LOG_IN_REQUEST,
data
}
};
export const signupRequestAction = (data) => {
return {
type: SIGN_UP_REQUEST,
data
}
};
export const nicknameEditRequestAction = (data) => {
return {
type: NICKNAME_EDIT_REQUEST,
data
}
};
const reducer = (state = initialState, action) => {
return produce(state, (draft) => {
switch (action.type) {
case LOG_IN_REQUEST:
draft.logInLoading = true;
draft.logInDone = false;
draft.logInError = null;
break;
case LOG_IN_SUCCESS:
draft.logInLoading = false;
draft.logInDone = true;
draft.me = dummyUser(action.data);
break;
case LOG_IN_FAILURE:
draft.logInLoading = false;
draft.logInError = action.error;
break;
case LOG_OUT_REQUEST:
draft.logOutLoading = true;
draft.logOutDone = false;
draft.logOutError = null;
break;
case LOG_OUT_SUCCESS:
draft.logOutLoading = false;
draft.logOutDone = true;
draft.me = null;
break;
case LOG_OUT_FAILURE:
draft.logOutLoading = false;
draft.logOutError = action.error;
break;
case SIGN_UP_REQUEST:
draft.signUpLoading = true;
draft.signUpDone = false;
draft.signUpError = null;
break;
case SIGN_UP_SUCCESS:
draft.signUpLoading = false;
draft.signUpDone = true;
break;
case SIGN_UP_FAILURE:
draft.signUpLoading = false;
draft.signUpError = action.error;
break;
case NICKNAME_EDIT_REQUEST:
draft.nicknameEditLoading = true;
draft.nicknameEditDone = false;
draft.nicknameEditError = null;
break;
case NICKNAME_EDIT_SUCCESS:
draft.me.nickname = action.data.nicknameEdit;
draft.nicknameEditLoading = false;
draft.nicknameEditDone = true;
break;
case NICKNAME_EDIT_FAILURE:
draft.nicknameEditLoading = false;
draft.nicknameEditError = action.error;
break;
case SCRAP_ADD_POST_TO_ME:
draft.me.Scrap.unshift(dummyPost(action.data));
break;
case SCRAP_REMOVE_POST_OF_ME:
draft.me.Scrap = draft.me.Scrap.filter((v) => v.id !== action.data);
break;
case BOARD_ADD_POST_TO_ME:
draft.me.Board.unshift(dummyPost(action.data));
break;
case BOARD_REMOVE_POST_OF_ME:
draft.me.Board = draft.me.Board.filter((v) => v.id !== action.data);
break;
default:
break;
}
});
};
export default reducer;
sagas/user.js
import { all, fork, delay, put, takeLatest, call } 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,
NICKNAME_EDIT_REQUEST, NICKNAME_EDIT_SUCCESS, NICKNAME_EDIT_FAILURE,
} from '../reducers/user';
// function logInAPI(data) {
// return axios.post('/api/login', data);
// }
function* logIn(action) {
try {
// const result = yield call(logInAPI, action.data);
yield delay(1000);
yield put({
type: LOG_IN_SUCCESS,
data: action.data,
})
} catch(err) {
yield put({
type: LOG_IN_FAILURE,
error: err.response.data
})
}
}
// function logOutAPI() {
// return axios.post('/api/logout');
// }
function* logOut() {
try {
// const result = yield call(logOutAPI);
yield delay(1000);
yield put({
type: LOG_OUT_SUCCESS,
})
} catch(err) {
yield put({
type: LOG_OUT_FAILURE,
error: err.response.data
})
}
}
function signUpAPI(data) {
console.log('signUpAPI 실행');
return axios.post('/user', data);
}
function* signUp(action) {
console.log('signUp 실행');
try {
const result = yield call(signUpAPI, action.data);
console.log(result);
yield put({
type: SIGN_UP_SUCCESS,
})
} catch(err) {
console.log(err);
yield put({
type: SIGN_UP_FAILURE,
error: err.response.data
})
}
}
// function NicknameEditAPI() {
// return axios.post('/api/NicknameEdit');
// }
function* nicknameEdit(action) {
try {
// const result = yield call(NicknameEditAPI);
console.log(action.data);
yield delay(1000);
yield put({
type: NICKNAME_EDIT_SUCCESS,
data: action.data,
})
} catch(err) {
yield put({
type: NICKNAME_EDIT_FAILURE,
error: err.response.data
})
}
}
function* watchLogIn() {
yield takeLatest(LOG_IN_REQUEST, logIn);
}
function* watchLogOut() {
yield takeLatest(LOG_OUT_REQUEST, logOut);
}
function* watchSignUp() {
console.log('watchSignUp 실행');
yield takeLatest(SIGN_UP_REQUEST, signUp);
}
function* watchNicknameEdit() {
yield takeLatest(NICKNAME_EDIT_REQUEST, nicknameEdit);
}
export default function* userSaga() {
yield all([
fork(watchLogIn),
fork(watchLogOut),
fork(watchSignUp),
fork(watchNicknameEdit),
]);
}
back/app.js
const express = require('express');
const cors = require('cors');
const postRouter = require('./routes/post');
const userRouter = require('./routes/user');
const db = require('./models')
const app = express();
db.sequelize.sync()
.then(() => {
console.log('db 연결 성공');
})
.catch(console.error);
app.use(cors({
origin: true,
}));
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
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('서버 실행 중');
});
back/routes/user.js
const express = require('express');
const bcrypt = require('bcrypt');
const { User } = require('../models');
const router = express.Router();
router.post('/', async(req, res, next) => {
try {
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, 10);
await User.create({
email: req.body.email,
password: hashedPassword,
nickname: req.body.nickname,
});
res.status(200).send('OK');
} catch (error) {
console.error(error);
next(error);
}
});
module.exports = router;
back/models/user.js
const DataTypes = require('sequelize');
const { Model } = DataTypes;
module.exports = class User extends Model {
static init(sequelize) {
return super.init({
email: {
type: DataTypes.STRING(30),
allowNull: false,
unique: true,
},
nickname: {
type: DataTypes.STRING(30),
allowNull: false,
},
password: {
type: DataTypes.STRING(100),
allowNull: false,
},
}, {
modelName: 'User',
tableName: 'users',
charset: 'utf8',
collate: 'utf8_general_ci',
sequelize,
});
}
static associate(db) {
db.User.hasMany(db.Post);
db.User.hasMany(db.Comment);
db.User.belongsToMany(db.Post, { through: 'Like', as: 'Liked' })
}
};
답변 1
0
해당 강의에서 회원가입을 구현하신 뒤 회원가입을 수행하면 네트워크탭에 name: user, method: post가 표시되는데, 제 네트워크탭에서는 아무런 표시가안되고 있습니다.
표시안되는이유가 routes/user에서 작성한 post요청이 정상적으로 안되서 그런건지 그 이유에 대해 궁금해서 질문드렸습니다.
router.post('/', async(req, res, next) => {
try {
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, 10);
await User.create({
email: req.body.email,
password: hashedPassword,
nickname: req.body.nickname,
});
res.status(200).send('OK');
} catch (error) {
console.error(error);
next(error);
}
});
정상적으로 실행되고 있었네요.. 진짜 바보같은 질문을 드렸습니다 바쁘신데 죄송합니다 ㅜㅜ
추가로 passport login을 구현해서 실행했는데 로그인, 회원가입시 둘다 아래와 같은 서버 에러가 발생하는데 어떤 이유때문에 발생했는지 알 수 있을까요?
구글링으로 계속 찾고있는데 답을 찾기힘들어서 질문드립니다 ㅜㅜ
.png)



<관련코드>
back/app.js
const express = require('express');
const cors = require('cors');
const passport = require('passport');
const session = require('express-session');
const cookieParser = require('cookie-parser');
const dotenv = require('dotenv');
const postRouter = require('./routes/post');
const userRouter = require('./routes/user');
const db = require('./models')
const app = express();
const passportConfig = require('./passport');
dotenv.config();
db.sequelize.sync()
.then(() => {
console.log('db 연결 성공');
})
.catch(console.error);
passportConfig();
app.use(cors({
origin: true,
}));
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(passport.initialize());
app.use(passport.session({
saveUninitialized: false,
resave: false,
secret: process.env.COOKIE_SECRET,
}));
app.use(cookieParser(process.env.COOKIE_SECRET));
app.use(session());
app.use('/post', postRouter);
app.use('/user', userRouter);
app.listen(3065, () => {
console.log('서버 실행 중');
});
routes/user.js
const express = require('express');
const bcrypt = require('bcrypt');
const passport = require('passport');
const { User } = require('../models');
const router = express.Router();
router.post('/login', (req, res, next) => {
passport.authenticate('local', (err, user, info) => {
if (err) {
console.error(err);
return next(err);
}
if (info) {
return res.status(401).send(info.reason);
}
return req.logIn(user, async (loginErr) => {
if (loginErr) {
console.error(loginErr);
return next(loginErr);
}
return res.status(200).json(user);
});
})(req, res, next);
});
module.exports = router;
passport/index.js
const passport = require('passport');
const local = require('./local');
const { User } = require('../models');
module.exports = () => {
passport.serializeUser((user, done) => {
done(null, user.id);
});
passport.deserializeUser(async (id, done) => {
try {
const user = await User.findOne({
where: { id }
})
done(null, user);
} catch (error) {
console.error(error);
done(error);
}
});
local();
};
passport/local.js
const passport = require('passport');
const { Strategy: LocalStrategy } = require('passport-local');
const bcrypt = require('bcrypt');
const { User } = require('../models');
module.exports = () => {
passport.use(new LocalStrategy({
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, user);
}
return done(null, false, { reason: '비밀번호가 틀렸습니다.' })
} catch (error) {
console.error(error);
return done(error);
}
}));
};




명절인데도 빠른 답변 정말 감사합니다!!
첫 빌드시 콘솔에는 다음과 같은 에러가뜨는데 해당 에러가
user router실행되지 않는 문제랑 연관이 있는걸까요?