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

使用Axios请求服务器遇404错误,动态路由下/api/dashboard无法访问

动态路由下Axios请求/api/dashboard返回404的问题

我尝试为每个用户创建动态路由localhost:3000/{dynamicId}/userPage,但在UserPage组件中使用Axios发送GET请求到api/dashboard时返回404错误。服务器端已定义/dashboard路由,且通过UUID生成的dynamicId已作为动态路由参数配置,疑惑为何提示该路由不存在。

相关代码

App.jsx

import { useState } from 'react'
import reactLogo from './assets/react.svg'
import './App.css'
import LoginPage from "./pages/LoginPage"
import { BrowserRouter, Routes, Route } from "react-router-dom";
import HomePage from './pages/HomePage';
import SignUpPage from './pages/SignUpPage'
import UserPage from './pages/UserPage';

function App() {
  return (
    <>
      <BrowserRouter>
        <Routes>
          <Route exact path="/" element={<HomePage/>}/>
          <Route path="login" element={<LoginPage/>}/>
          <Route path="signup" element={<SignUpPage/>}/>
          <Route path=":user/userpage" element={<UserPage />} />
        </Routes>
      </BrowserRouter>
    </>
  )
}

export default App

UserPage.jsx

import axios from "axios"
import Button from "../Shared/FormElement/Button"
import { useEffect, useState } from "react";
import { useNavigate } from "react-router-dom";

function UserPage(props) {
  const[isLoading,setIsLoading]=useState(false)
  const[isLoggedin, setIsLoggedin]=useState(false)
  
  const handleLoad=(event)=>{
    setIsLoading(true)
    axios({
      method: "get",
      url: "api/dashboard",
    })
    .then((response) => {
      console.log("UserLoggedin:",response.data)
      setIsLoading(false)
      setIsLoggedin(true)
      if (!response.data) {
        navigate("/login")
      }
    })
  }
  
  const navigate = useNavigate();
  useEffect(() => {
    console.log("being called")
    handleLoad()
  }, []);
  
  function handleclick(event){
    axios({
      method: "post",
      url: "api/logout"
    }).then((response) => {
      console.log(response.data)
      if (!response.data)
        navigate("/login")
    })
  }
  
  return isLoggedin&&<div>
      <h1>Hello User</h1>
      <Button type="submit" style="primary" onClick={handleclick}> Logout</Button>
      {isLoading &&<h2>Loading...</h2>}
  </div>
}

export default UserPage

vite.config.js

import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'

export default defineConfig({
  plugins: [react()],
  server: {
    proxy: {
      '/api': {
        target: 'http://localhost:3000',
        changeOrigin: true,
        rewrite: (path) => path.replace(/^\/api/, '')
      }
    }
  }
})

服务器端代码

require('dotenv').config()
const { v4: uuidv4 } = require('uuid');
const bodyParser = require("body-parser")
const express = require("express")
const passport = require('passport');
const LocalStrategy = require('passport-local').Strategy;
const GoogleStrategy = require('passport-google-oauth20').Strategy;
const app = express()
const mongoose = require('mongoose');
const cors = require('cors');
const bcrypt = require('bcrypt');
const session = require('express-session');
const saltRounds = 10;

app.use(bodyParser.urlencoded({ extended: true }))
app.use(bodyParser.json());
app.use(cors())
PORT = process.env.PORT || 3000

app.use(session({
    secret: process.env.SECRET,
    resave: false,
    saveUninitialized: true,
}))

app.use(passport.initialize())
app.use(passport.session())

const authUser = (email, password, done) => {
    Account.findOne({ Email: email }).exec()
        .then((account) => {
            if (account) {
                bcrypt.compare(password, account.Password).then(function (result) {
                    if (result) {
                        done(null, { account }, { message: "Succesfull" })
                    }
                    else {
                        done(null, false, { message: "Invalid password" })
                    }
                })
            }
            else {
                done(null, false, { message: "Invalid password" })
            }
        })
        .catch((error) => done(error));
}

passport.use(new LocalStrategy({
    usernameField: 'email',
    passwordField: 'password'
},authUser))

passport.serializeUser((userObj, done) => {
    done(null, userObj.account.id);
});

passport.deserializeUser((userId, done) => {
    Account.findOne({ id: userId })
      .exec()
      .then((account) => {
        done(null, { account });
      })
      .catch((error) => done(error));
});

const { Schema, model } = mongoose;
const MongooseConnect = async () => {
    try {
        const conn = await mongoose.connect(process.env.MONGODBBKEY);
        console.log(`MongoDB Connected: ${conn.connection.host}`)
    } catch (error) {
        console.log(error)
        process.exit(1)
    }
}

const user_accounts = new Schema({
    id:String,
    first_name: String,
    last_name: String,
    Email: String,
    Password: String
})
const Account = model("Account", user_accounts)

app.post("/login", (req, res, next) => {
  passport.authenticate("local", (err, user, info) => {
    if (user) {
      req.logIn(user, (err) => {
        if (err) {
          return next(err);
        }
        console.log(user, info);
        console.log(req.isAuthenticated());
        console.log(user.account.id);
        return res.json({
          id: user.account.id,
          authentication: true,
        });
      });
    } else {
      console.log(user, info);
      return res.json({
        id: user.account.id,
        authentication: false,
      });
    }
  })(req, res, next);
});

app.get("/dashboard",(req,res,next)=>{
  console.log(req.isAuthenticated())
  res.json(req.isAuthenticated())
})

app.post('/logout', function(req, res, next){
  req.logout(function(err) {
    if (err) { return next(err); }
    console.log(req.isAuthenticated())
    res.json(req.isAuthenticated())
  });
});

app.post("/signup", async (req, res, next) => {
    Account.findOne({ Email: req.body.Email }).exec()
        .then((account) => {
            if (!account) {
                bcrypt.hash(req.body.password, saltRounds).then(function (hash) {
                    const user = Account({
                        id:uuidv4(),
                        first_name: req.body.first_name,
                        last_name: req.body.lastname,
                        Email: req.body.Email,
                        Password: hash,
                    })
                    user.save()
                });
                console.log("User Created");
                const Accountexist = false
                res.json(Accountexist)
            }
            else {
                console.log("Account Exist")
                const Accountexist = true
                res.json(Accountexist)
            }
        })
})

MongooseConnect().then(
  app.listen(PORT, () => {
    console.log(`Working in port ${PORT}`)
  })
)

错误截图

请求404错误截图


问题原因与解决方案

1. 核心问题:相对路径解析错误

你在UserPage里写的请求URL是"api/dashboard",这是相对路径。当页面处于localhost:3000/abc123/userpage这种多层路由下时,浏览器会把请求路径拼接成localhost:3000/abc123/api/dashboard——这显然不是后端定义的/dashboard路由,所以返回404。

解决办法:给所有API请求的URL加上开头的斜杠,改成绝对路径:

// 修改dashboard请求
axios({
  method: "get",
  url: "/api/dashboard", // 注意开头的/
})

// 修改logout请求
axios({
  method: "post",
  url: "/api/logout" // 同样加/
})

2. 额外排查点:端口与代理配置

你的Vite代理配置是对的,把/api开头的请求转发到后端3000端口,但要确保:

  • 后端确实运行在3000端口,Vite开发服务器运行在其他端口(比如默认的5173),避免端口冲突
  • 代理的rewrite规则正确:path.replace(/^\/api/, '')会把/api/dashboard转成/dashboard,和后端路由匹配

3. 潜在问题:会话凭证传递

如果后续请求/dashboard返回未授权,需要确保会话Cookie能正确传递:

  • 前端Axios请求加上withCredentials: true
  • 后端CORS配置指定允许的Origin并开启凭证支持

修改示例:

// 前端请求添加凭证
axios({
  method: "get",
  url: "/api/dashboard",
  withCredentials: true
})

// 后端修改CORS配置
app.use(cors({
  origin: "http://localhost:5173", // Vite服务器地址
  credentials: true
}))

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 05:27:21