You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

登录功能异常排查:userInfo显示undefined及请求媒体类型错误

登录功能开发问题排查

问题描述

  1. userInfo 始终为 undefined:使用Postman发送POST请求可正常获取用户信息及token,但Redux DevTools中无对应状态数据显示
  2. 登录请求报错:Unsupported media type "application/x-www-form-urlencoded, application/json" in request

相关代码

userReducers.js

export const userLoginReducers = (state = {}, action) => {
  switch (action.type) {
    case USER_LOGIN_REQUEST:
      return { laoding: true };
    case USER_LOGIN_SUCCESS:
      return { laoding: false, userInfo: action.payload };
    case USER_LOGIN_FAIL:
      return { laoding: false, error: action.payload };

    case USER_LOGOUT:
      return {};

    default:
      return state;
  }
};

userActions.js

export const login = (email, password) => async (dispatch) => {
  try {
    dispatch({
      type: USER_LOGIN_REQUEST,
    });

    const config = {
      headers: {
        "Content-type": "application/json",
      },
    };

    const { data } = await axios.post(
      "/api/users/login/",
      { username: email, password: password },
      config
    );

    dispatch({
      type: USER_LOGIN_SUCCESS,
      payload: data,
    });

    localStorage.setItem("userInfo", JSON.stringify(data));
  } catch (error) {
    dispatch({
      type: USER_LOGIN_FAIL,
      payload:
        error.response && error.response.data.detail
          ? error.response.data.detail
          : error.message,
    });
  }
};

Store.js

import {
  legacy_createStore as createStore,
  combineReducers,
  applyMiddleware,
} from "redux";
//import { configureStore } from "@reduxjs/toolkit";
import thunk from "redux-thunk";
import { composeWithDevTools } from "redux-devtools-extension";
import {
  productListReducers,
  productDetailsReducers,
} from "./reducers/ProductReducers";
import { cartReducer } from "./reducers/CartReducers";
import { userLoginReducers } from "./reducers/UserReducers";

const reducer = combineReducers({
  productList: productListReducers,
  productDetails: productDetailsReducers,
  cart: cartReducer,
  userLogin: userLoginReducers,
});

const cartItemsFromStorage = localStorage.getItem("cartItems")
  ? JSON.parse(localStorage.getItem("cartItems"))
  : [];

const userInfoFromStorage = localStorage.getItem("userInfo")
  ? JSON.parse(localStorage.getItem("userInfo"))
  : null;

const initialState = {
  cart: { cartItems: cartItemsFromStorage },
  userLogin: { userInfo: userInfoFromStorage },
};
const middleware = [thunk];
const store = createStore(
  reducer,
  initialState,
  composeWithDevTools(applyMiddleware(...middleware))
);

export default store;

LoginScreen.js

import React, { useState, useEffect } from "react";
import { Link } from "react-router-dom";
import { useDispatch, useSelector } from "react-redux";
import { Row, Col, Button, Form } from "react-bootstrap";
//import products from "../../products";
import Message from "../Message";
import Loader from "../Loader";
import { useNavigate, useLocation, useSearchParams } from "react-router-dom";
import { login } from "../../actions/UserActions";
import LoginForm from "../LoginForm";

function LoginScreen() {
  const [searchParams, setSearchParams] = useSearchParams();
  const { search } = useLocation();
  const navigate = useNavigate();
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");
  const dispatch = useDispatch();

  const redirect = searchParams.get(search.split("=")) || 1;

  const userLogin = useSelector((state) => state.userLogin);
  const { error, loading, userInfo } = userLogin;

  useEffect(() => {
    if (userInfo) {
      navigate(redirect);
      setSearchParams(searchParams);
    }
  }, [navigate, userInfo, redirect, searchParams, setSearchParams]);

  const submitHandler = (e) => {
    e.preventDefault();
    dispatch(login(email, password));
  };

  return (
    <LoginForm>
      <h1>Sign In</h1>
      {error && <Message variant="danger">{error}</Message>}
      {loading && <Loader />}

      <Form onSubmit={submitHandler}>
        <Form.Group>
          <Form.Label>Email Address</Form.Label>
          <Form.Control
            type="email"
            placeholder="Enter Email"
            value={email}
            onChange={(e) => setEmail(e.target.value)}
          ></Form.Control>
        </Form.Group>

        <Form.Group controlId="password">
          <Form.Label>Password</Form.Label>
          <Form.Control
            type="password"
            placeholder="Enter Password"
            value={password}
            onChange={(e) => setPassword(e.target.value)}
          ></Form.Control>
        </Form.Group>

        <Button type="submit" className="mt-3" variant="primary">
          Sign In
        </Button>
      </Form>

      <Row className="py-3">
        <Col>
          New Customer?
          <Link to={redirect ? `/register?redirect=${redirect}` : "/register"}>
            Register
          </Link>
        </Col>
      </Row>
    </LoginForm>
  );
}

export default LoginScreen;

问题分析与解决方案

问题2:Unsupported media type错误(优先解决)

这个错误是请求格式不兼容导致的,后端无法识别同时包含两种类型的请求头:

  1. 确认后端支持的Content-Type:
    • 如果后端仅接受application/x-www-form-urlencoded,修改userActions.js中的请求配置:
      import qs from 'qs'; // 需要先安装qs库:npm install qs
      
      // ...
      const { data } = await axios.post(
        "/api/users/login/",
        qs.stringify({ username: email, password: password }), // 转换为表单格式
        { headers: { "Content-type": "application/x-www-form-urlencoded" } }
      );
      
    • 如果后端接受application/json,检查是否有axios拦截器或其他代码篡改了请求头,导致同时添加了两种Content-Type

问题1:userInfo undefined与Redux DevTools无数据

这个问题和请求失败直接相关(请求失败不会触发USER_LOGIN_SUCCESS),同时存在代码拼写错误:

  1. 修正reducer中的拼写错误:所有laoding都拼错成了loading,这会导致组件中useSelector获取loading状态失败,同时Redux状态结构异常:
    // 修正后的userReducers.js关键部分
    case USER_LOGIN_REQUEST:
      return { loading: true };
    case USER_LOGIN_SUCCESS:
      return { loading: false, userInfo: action.payload };
    case USER_LOGIN_FAIL:
      return { loading: false, error: action.payload };
    
  2. 验证action常量一致性:确保USER_LOGIN_REQUEST、USER_LOGIN_SUCCESS等常量在reducer和action中完全一致(比如大小写、拼写),否则reducer无法正确匹配action
  3. 检查Redux DevTools连接:确认composeWithDevTools正确包裹了中间件,store配置无误

关联性说明

media type错误会导致请求失败,进入USER_LOGIN_FAIL分支,不会触发USER_LOGIN_SUCCESS更新userInfo,因此两个问题直接相关:先解决请求格式错误,让请求成功,再验证Redux状态更新是否正常


内容的提问来源于stack exchange,提问作者Khaled

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 00:10:35