Получение кода состояния 304 при получении информации о текущем пользователе с сервера - PullRequest
1 голос
/ 27 января 2020

Итак, у меня есть это простое приложение для аутентификации, в котором я использую Node.js, Express. js, MongoDB, React. js и Redux. js. Пользователь может зарегистрироваться и войти в систему. У меня возникли проблемы с получением информации о текущем пользователе.

После входа в систему, когда я обновляю sh браузера, маршрут / me попадает и возвращает текущего вошедшего в систему пользователя. Но проблема в том, что он показывает только пользователя, которого я вошел в первый раз. Это дает мне 200 кодов статуса в первый раз, но 304 после каждого другого входа. Я знаю, 304 означает «не модифицированный» ответ. Когда я проверяю вкладку сети, то ответ тот же (первый вошедший в систему пользователь).

Я развернул свой проект в песочнице кода здесь . Пожалуйста, загрузите его и запустите на своей локальной системе (он показывает плохой шлюз на Codesandbox). Я застрял в этом вопросе в течение длительного времени.

usersController.js

    loginUser: (req, res, next) => {
        const { email, password } = req.body

        if (!email || !password) {
            return res.status(400).json({ message: "Email and password are must" })
        }

        User.findOne({ email }, (err, user) => {
            if (err) {
                return next(err)
            } else if (!validator.isEmail(email)) {
                return res.status(400).json({ message: "Invalid email" })
            } else if (!user) {
                return res.status(402).json({ error: "User not found" })
            } else if (!user.confirmPassword(password)) {
                return res.status(402).json({ error: "Incorrect password" })
            }

            // generate token here
            const token = auth.signToken({ userId: user._id })
            res.status(200).json({ user, token })
            // next()
        })
    },

    identifyUser: (req, res, next) => {
        const userId = req.userId
        // const token = req.body.token

        // if (!token) {
        //     return res.status(401).json({message: "Must pass token"})
        // }

        User.findOne(userId, (err, user) => {
            if (err) return next(err)
            return res.json({ currentUser: user })
        })
    }
utils/auth.js

const jwt = require("jsonwebtoken")

function signToken(payload) {
    console.log("inside signToken")
    return jwt.sign(payload, process.env.JWTSECRET)
}

function verifyToken(req, res, next) {
    // console.log("inside verifyToken")
    const token = req.headers.Authorization || req.headers.authorization || ""
    console.log(token, "inside verifyToken")
    if (!token) {
        return res.status(403).json({ error: "Not authorized"})
    }

    jwt.verify(token, process.env.JWTSECRET, (err, decodedObj) => {
        if (err) {
            return res.status(403).json({ error: "Not authorized" })
        }

        req.user = decodedObj
        console.log(req.user, decodedObj)
        next()  
    })
}


module.exports = { signToken, verifyToken }
actions/index.js

export const loginUser = (loginData) => {
    console.log("inside login action")
    return async dispatch => {
        dispatch({ type: "AUTH_STARTS" })

        try {
            const res = await axios.post("http://localhost:3000/api/v1/users/login", loginData)
            dispatch({
                type: "AUTH_SUCCESS",
                data: { user: res.data }
            })

            localStorage.setItem("authToken", res.data.token)

        } catch (err) {
            dispatch({
                type: "AUTH_ERROR",
                data: { error: "Something went wrong" }
            })
        }
    }
}



export const getCurrentUser = (token) => {
    // console.log("inside getCurrentUser action", token)
    return async dispatch => {
        dispatch({ type: "AUTH_STARTS" })
        try {
            // console.log("try block")
            const res = await axios.get("http://localhost:3000/api/v1/users/me", {
                headers: {
                    "Authorization": token
                }
            })
            dispatch({
                type: "AUTH_SUCCESS",
                data: { user: res.data }
            })

            dispatch({
                type: "SET_CURRENT_USER",
                data: { currentUser: res.data, currentUserName: res.data.currentUser.username }
            })

            console.log(user)
        } catch (err) {
            dispatch({
                type: "AUTH_ERROR",
                data: { error: "Something went wrong" }
            })
        }
    }
}



export const logoutUser = () => {
    return dispatch => {
        dispatch({type: "LOGOUT_USER"})
    }
}
reducers/auth.js

const initialState = {
    isAuthInProgress: false,
    isAuthenticated: false,
    authError: null,
    user: null,
    isIdentifyingToken: false,
    currentUser: null,
    isUserLoggedIn: "",
    token: "",
    // currentUserName: ""
}


const auth = (state=initialState, action) => {
    switch(action.type) {
        case "AUTH_STARTS":
            return {...state,
                 isAuthInProgress: true,
                 authError: null,
                 isLoggingInUser: true
                }

        case "AUTH_SUCCESS":
            return {...state,
                isAuthInProgress: false,
                authError: null,
                isAuthenticated: true,
                user: action.data,
                isIdentifyingToken: false,
                isUserLoggedIn: true,
                // isLoggingInUser: false
            }

        case "AUTH_ERROR":
            return {...state,
                isAuthInProgress: false,
                authError: action.data.error,
                isAuthenticated: false,
                user: null
            }

        case "TOKEN_VERIFICATION_STARTS":
            return {...state,
                isAuthInProgress: true,
                authError: null,
                isIdentifyingToken: true
            } 

        case "SET_CURRENT_USER":
            return {...state,
                isAuthInProgress: false,
                isAuthenticated: true,
                authError: null,
                currentUser: action.data.currentUser,
                isUserLoggedIn: true,
                currentUserName: action.data.currentUserName
            }
        case "LOGOUT_USER":
            return {...state,
                isUserLoggedIn: false,
                token: localStorage.removeItem("authToken")
            }

        default: 
            return state  
    }
}


export default auth
LoginForm.js


import React, { Component } from "react"
import validator from "validator"
import { loginUser } from "../actions/index"
import { connect } from "react-redux"

class LoginForm extends Component {

    constructor(props) {
        super(props)
        this.state = {
            email: "",
            password: ""
        }
    }

    handleChange = (event) => {
        const { name, value } = event.target
        this.setState({
            [name]: value
        })
    }

    handleSubmit = (event) => {
        event.preventDefault();
        const { email, password } = this.state;

        const loginData = {
            email: this.state.email,
            password: this.state.password
        }

        if (!email || !password) {
            return alert('Email and password are must.');
        }

        if (password.length < 6) {
            return alert('Password must contain 6 characters.');
        }

        if (!validator.isEmail(email)) {
            return alert('Invalid email.');
        }

        this.props.dispatch(loginUser(loginData))

        this.props.history.push("/")
    }

    render() {
        const isAuthInProgress = this.props.auth.isAuthInProgress
        return (
            <div>
                <div className="field">
                    <p className="control has-icons-left has-icons-right">
                        <input className="input" onChange={this.handleChange} name="email" value={this.state.email} type="email" placeholder="Email" />
                        <span className="icon is-small is-left">
                            <i className="fas fa-envelope"></i>
                        </span>
                        <span className="icon is-small is-right">
                            <i className="fas fa-check"></i>
                        </span>
                    </p>
                </div>
                <div className="field">
                    <p className="control has-icons-left">
                        <input className="input" onChange={this.handleChange} name="password" value={this.state.password} type="password" placeholder="Password" />
                        <span className="icon is-small is-left">
                            <i className="fas fa-lock"></i>
                        </span>
                    </p>
                    <p className="has-text-danger">Forgot password?</p>
                </div>
                <div className="field">
                    <p className="control">
                        {
                            isAuthInProgress ? <p>Logging in...</p>
                        :
                        <button onClick={this.handleSubmit} className="button is-success">
                            Login
                        </button>
                        }   
                    </p>

                </div>
            </div >
        )
    }
}

const mapStateToProps = (state) => {
    return state
}


export default connect(mapStateToProps)(LoginForm)
App.js


import React, { Component } from "react"
import { BrowserRouter as Router, Route, Switch } from "react-router-dom"
import LandingPage from "./components/LandingPage"
import RegistrationForm from "./components/RegistrationForm"
import LoginForm from "./components/LoginForm"
import NotFoundPage from "./components/NotFoundPage"
import { getCurrentUser } from "./actions"
import { connect } from "react-redux"

class App extends Component {

    componentDidMount() {
        const authToken = localStorage.getItem("authToken")

        if (authToken) {
            this.props.dispatch({ type: "TOKEN_VERIFICATION_STARTS" })
            this.props.dispatch(getCurrentUser(authToken))
        }
    }

    render() {
        const isIdentifyingToken = this.props.auth.isIdentifyingToken
        return (
            <div>
                {
                    isIdentifyingToken ? null
                        :
                        <Router>
                            <Switch>
                                <Route exact path="/" component={LandingPage} />
                                <Route path="/register" component={RegistrationForm} />
                                <Route path="/login" component={LoginForm} />
                                <Route component={NotFoundPage} />
                            </Switch>
                        </Router>
                }

            </div>
        )
    }
}

const mapStateToProps = (state) => {
    return state
}
export default connect(mapStateToProps)(App)
Header.js


import React from "react"
import { Link, withRouter } from "react-router-dom"
import {connect} from "react-redux"
import {logoutUser} from "../actions/index"

class Header extends React.Component {


    handleLogout = () => {
        this.props.dispatch(logoutUser())
        this.props.history.push("/")
    }


    render() {
    const isUserLoggedIn = this.props.auth.isUserLoggedIn

        return (
        <nav className="navbar is-clearfix is-fixed-top" role="navigation" aria-label="main navigation">
            <div className="navbar-brand">
                <Link to="/" className="navbar-item" href="https://bulma.io">
                    <h1 className="has-text-weight-semibold is-family-primary is-size-5 is-size-6-mobile is-family-sans-serif"></h1>
                </Link>

                <a role="button" className="navbar-burger burger" aria-label="menu" aria-expanded="false" data-target="navbarBasicExample">
                    <span aria-hidden="true"></span>
                    <span aria-hidden="true"></span>
                    <span aria-hidden="true"></span>
                </a>
            </div>

            <div id="navbarBasicExample" className="navbar-menu">
                <div className="navbar-start">
                    <div className="navbar-item has-dropdown is-hoverable is-active">
                    </div>
                </div>
                <div className="navbar-end">
                    <div className="navbar-item">
                        <div className="buttons">
                            {   
                                isUserLoggedIn? 
                            <button onClick={this.handleLogout} className="button is-sucess">
                                <strong>Logout</strong>
                            </button>
                            :
                            <div>
                                <Link to="/register" className="button is-success">
                                    <strong >Sign up</strong>
                                </Link>
                                <Link to="/login" className="button is-sucess">
                                    <strong>Sign in</strong>
                                </Link>
                            </div>
                            }
                        </div>
                    </div>
                </div>
            </div>
        </nav>
    )
}
}


const mapStateToProps = (state) => {
    return state
}


export default withRouter(connect(mapStateToProps)(Header))

Редактировать : не беспокойтесь , исправил!

1 Ответ

0 голосов
/ 27 января 2020

У меня нет проблемы, о которой вы говорите, поэтому я предполагаю, что это проблема с вашим кешем ¯ \ _ (ツ) _ / ¯

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...