-> axios 호출 시 여러 번 같은 주소 써야 함(redux-saga)
-> redux-saga에서 baseURL 방법
import { all } from "redux-saga/effects";
import { userSagas } from "./userSaga";
import { wordSagas } from "./wordSaga";
import { postSagas } from "./postSaga";
import { gameSaga } from "./gameSaga";
import axios from "axios";
axios.defaults.baseURL = "http://localhost:3005"; //서버 포트
export default function* rootSaga() {
yield all([...userSagas, ...wordSagas, ...postSagas, ...gameSaga]);
}
session
npm i express-session
cookie-parser
npm i cookie-parser
로그인 하면 로그인을 누가 했는지 보내줘야 함
[server.js]
const express = require("express");
const cors = require("cors");
const session = require("express-session");
const cookieParser = require("cookie-parser");
const passport = require("passport");
const morgan = require("morgan");
const dotenv = require("dotenv");
const hpp = require("hpp");
const helmet = require("helmet");
const db = require("./models");
const passportConfig = require("./passport");
const wordRouter = require("./routes/word");
const userRouter = require("./routes/user");
dotenv.config();
const app = express();
//시퀄라이즈 연결
db.sequelize
.sync({ force: false }) //true면 서버 재시작 할 때마다 mysql 지워짐(default를 false로 고정할 것)
.then(() => {
console.log("DB 연결 성공");
})
.catch(console.error);
if (process.env.NODE_ENV === "production") {
app.use(morgan("combined"));
app.use(hpp());
app.use(helmet());
app.use(
cors({
origin: "나중에 연결할 도메인 이름"
credentials: true,
})
);
} else {
app.use(morgan("dev"));
app.use(
cors({
origin: "http://localhost:3000",
credentials: true,
})
);
}
passportConfig();
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(cookieParser(process.env.COOKIE_SECRET)); //쿠키 연결
app.use(
session({ //세션 연결
saveUninitialized: false,
resave: false,
secret: process.env.COOKIE_SECRET,
})
);
app.use(passport.initialize());
app.use(passport.session());
app.get("/", (req, res) => {
res.send("hello express");
});
app.use("/word", wordRouter);
app.use("/user", userRouter);
app.listen(3005, () => {
console.log("The server is running at port 3005");
});
[password/index.js]
const passport = require("passport");
const local = require("./local");
const { User } = require("../models"); //sequelize로 만든 모델 User
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); // req.user
} catch (error) {
console.error(error);
done(error);
}
});
local();
};
[password/local.js]
const passport = require("passport");
const { Strategy: LocalStrategy } = require("passport-local");
const bcrypt = require("bcrypt"); //비밀번호 암호화
const { User } = require("../models"); //sequelize로 만든 모델 User
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);
}
}
)
);
};
next-dev.js?3515:20 A non-serializable value was detected in an action, in the path:
payload
. Value: AxiosError {message: 'Request failed with status code 401', name: 'AxiosError', code: 'ERR_BAD_REQUEST', config: {…}, request: XMLHttpRequest, …}
Take a look at the logic that dispatched this action: {type: 'user/logoutFailure', payload: AxiosError, @@redux-saga/SAGA_ACTION: true}
(See https://redux.js.org/faq/actions#why-should-type-be-a-string-or-at-least-serializable-why-should-my-action-types-be-constants)
(To allow non-serializable values see: https://redux-toolkit.js.org/usage/usage-guide#working-with-non-serializable-data)
변경 전
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware().concat(sagaMiddleware),
serializableCheck: false
변경 후
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({ serializableCheck: false }).concat(sagaMiddleware),
axios 500 에러가 뜸
변경 전
router.post("/logout", (req, res) => {
req.logout();
req.session.destroy();
res.send("ok");
})
변경 후
router.post("/logout", (req, res) => {
req.logout((err) => {
req.session.destroy();
if (err) {
res.redirect("/");
} else {
res.status(200).send("server ok: 로그아웃 완료");
}
});
});
[userSaga.js]
import axios from "axios";
function logInAPI(data) {
return axios.post("/user/login", data);
}
function* logIn(action) {
try {
const data = action.payload;
const result = yield call(logInAPI, data);
console.log("result", result);
yield put(loginSuccess(result.data));
} catch (error) {
yield put(loginFailure(error));
console.log(error);
}
}
function logOutAPI() {
return axios.post("/user/logout");
}
function* logOut() {
try {
yield call(logOutAPI);
yield put(logoutSuccess());
} catch (error) {
yield put(logoutFailure(error));
console.log(error);
}
}
function signUpAPI(data) {
return axios.post("/user", data);
}
function* signUp(action) {
try {
const data = action.payload;
const result = yield call(signUpAPI, data);
console.log("result", result);
yield put(signupSuccess());
// yield call(signupSuccess, data);
} catch (error) {
yield put(signupFailure(error));
console.log(error);
}
}
function* login_Req() {
yield takeLatest(loginRequest.type, logIn);
}
function* logout_Req() {
yield takeLatest(logoutRequest.type, logOut);
}
function* signup_Req() {
yield takeLatest(signupRequest.type, signUp);
}
export const userSagas = [fork(login_Req), fork(logout_Req), fork(signup_Req)];
[userSlice.js - redux-toolkit]
//회원가입
signupSuccess: (state) => {
state.me = null;
state.signupLoading = false;
state.signupComplete = true;
},
//로그인
loginSuccess: (state, action) => {
state.loginLoading = false;
state.loginComplete = true;
state.me = action.payload;
console.log("state.me", state.me);
},
//로그아웃
logoutSuccess: (state) => {
state.me = null;
state.logoutLoading = false;
state.logoutComplete = true;
},