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

ReactJS线上出现软导航检测错误,本地运行正常求排查

React路由线上部署导航异常问题排查

我开发了一个包含accounts.js和accountView.js的简单React应用,通过以下代码从accounts.js向accountView.js传递ID:

<td><FaPencilAlt/> <FaTrashAlt/><Link to={"/accounts"+"/"+x.id }><AiFillDiff/></Link></td>

本地localhost运行正常,但部署到线上服务器后无法正常工作,出现错误提示:检测到软导航:https://rwood.znapay.in/accounts/1。以下是我的Accounts.js和App.js代码:

Accounts.js

import React, { Component, useState, useEffect, useContext } from "react";
import {
  Card,
  Col,
  OverlayTrigger,
  Row,
  Tooltip,
  Table,
} from "react-bootstrap";
import { AiFillDiff } from "react-icons/ai";
import "datatables.net-dt/js/dataTables.dataTables.js";
import { AES, enc } from "crypto-js";
import Popup from 'reactjs-popup';
import 'reactjs-popup/dist/index.css';
import "datatables.net-responsive-dt";
import "datatables.net-dt/css/jquery.dataTables.min.css";
import "react-data-table-component-extensions/dist/index.css";
import { Link, useNavigate } from "react-router-dom";
import { TokenContext } from "../AuthProvider";
import $ from "jquery";
import axios from "axios";
import { BsFillEnvelopeFill } from "react-icons/bs";
import { FaPencilAlt, FaTrashAlt, FaPlus } from "react-icons/fa";
import { decryptedAccessToken, encryptedAccessToken } from "../../Token";
import Header from '../Header'
import Footer from '../Footer'
const AccountsList = () => {
  const navigate = useNavigate();

  const [formData, setFromdata] = useState({

    account_record: "",

  });


  const handleChange = (e) => {

    setFromdata({ ...formData, [e.target.name]: e.target.value });

  };

  const handleSubmit = (event) => {

    event.preventDefault();


    const encryptedAccessToken = localStorage.getItem('access_token');
    const secret_key = '4d3a23fba54bbef1e14dd44ba9591612';
    if (encryptedAccessToken) {
      const decryptedAccessToken = AES.decrypt(encryptedAccessToken, secret_key).toString(enc.Utf8);
      
    fetch('https://rwood.znapay.in:5000/add/record', {
              method: "POST",
              body: JSON.stringify(formData),
              headers: { Authorization: `Bearer ${decryptedAccessToken}`,
              'Content-Type': 'application/json' },
            })
              .then((response) => response.json())
              
              .then((response) => { 
                
                  console.log(response)
                  console.log(response.status)
                if (response.message === "record addedd successfully") {
                                  const account_record_new = response.account_type;
                                  
                                  navigate("/accounts/new-account", {
                        
                                    state: { account_record: account_record_new },
                        
                                  });
                        
                                }
              }) 
            } 
             
    };


  const body=$(window).height()
  const header=$("#header").height()
  const nav=$(".navbar").height()
  const footer=$(".footer").height()
  const total_height=header+nav+footer;
  const window_height=body-total_height;
  console.log(total_height)
  console.log(body)
  $(".addAccount").css({"min-height":(window_height)+"px"})
  const userRole = localStorage.getItem("role");
  console.log(userRole);
  const { username ,token} = useContext(TokenContext);
  const [datas, setDatas] = useState([]);

 
  useEffect(() => {
   
    fetchData();
  }, [decryptedAccessToken]);

  const fetchData = async () => {
    try {
      const response = await axios.get('https://rwood.znapay.in:5000/all/accounts', {
        headers: { Authorization: `Bearer ${decryptedAccessToken}` },        }
      );
      const data = response.data;
      console.log(data)
      setDatas(data);
      $(document).ready(function(){
        setTimeout(()=>{
          $('#tables').DataTable();
        },5)
      })
    } catch (error) {
      console.error(error);
    }
  };
  

  return (  
    <>
    <Header/>
    <div className="contactAccount">
      <div className="page-header" id='add-account'>
    <div>
      <h2 className="main-content-title tx-24 mg-b-5">Accounts </h2>
      <ol className="breadcrumb"> 
        <li className="breadcrumb-item active" aria-current="page">Dashboard / Accounts</li>
      </ol>
    </div>
    <div className="d-flex">
      <div className="justify-content-center">
          <Popup trigger={<button className="button add-accountrecord"> <FaPlus/> Add Account </button>} modal>
    
       <form onSubmit={handleSubmit} className="add-accounts">
        <div className='form-group'>
        <label>Account Record Type</label><br/>
        <select name='account_record' className='form-control' onChange={handleChange} value={formData.account_record}>
          <option >--Select account record type--</option>
          <option value='Agent'>Agent</option>
          <option value='Bank'>Bank</option>
          <option value='Buyer'>Buyer</option>
          
          <option value='Supplier'>Supplier</option>
          <option value='Competitor'>Competitor</option>
          <option value='Employee'>Employee</option>
          <option value='Surveyor'>Surveyor</option>
          </select>
          </div>
          <input type='submit' className="btn btn-primary " value='Submit'/>

          </form>
  </Popup>
      </div>
    </div> 
  </div> 
  <div class='tasks'>
  <table id='tables'>
    <thead>
    <tr>
      <th>Account Name</th>
      <th>Account Alias</th>
      <th>Account Record Type</th>
      <th>Origin</th>
      <th>Phone</th>
      <th>Port</th>
      <th>Actions</th>
    </tr>
    </thead>
    <tbody> 
      <React.Fragment>
      {datas.length > 0 ? (
  datas.map((x) => (
    <tr>
      <td>{x.account_name}</td>
      <td>{x.account_alias}</td>
      <td><span className='account-record'>{x.account_record_type}</span></td>  
      <td>{x.origin}</td>
      <td>{x.phone}</td>
      <td>{x.port}</td> 
      <td><FaPencilAlt/> <FaTrashAlt/><Link to={"/accounts"+"/"+x.id }><AiFillDiff/></Link></td>
    </tr>
  ))
) : (
  <tr>
    <td colSpan="6">No data available</td>
  </tr>
)}

      </React.Fragment>


    </tbody>
    </table>  
    </div> </div>  
    <Footer/>
    </>
  );
};

export default AccountsList;

App.js

import logo from './logo.svg';
import './App.css';

import 'bootstrap/dist/css/bootstrap.min.css'
import Header from './components/Header' 
import Footer from './components/Footer'
import OppShipmentList from './components/oppShipmentList'
import Login from './components/Login'
import Price from './components/price'
import AddProduct from './components/addproduct'
import Dashboard from './components/dashboard'
import Contactus from './components/account/contacts' 
 
import Accountlist from './components/accountlist' 
import AllTcf from './components/alltcf'   
import AccountDetails from './components/accountDetails'   
import Addaccount from './components/account/addaccount'
import Oppourtunity from './components/account/oppourtunity' 
import ResetPassword from './components/ResetPassword' 
import ResetConfirm from './components/ResetConfirm' 
import QuotesList from './components/quoteslist' 
import AddOppurtunity from './components/account/addoppurtunity' 
import AllQuotes from './components/account/allQuotes' 
import EditQuote from './components/account/editquote'
import ProductMaster from './components/productMaster/productmaster' 
import Shipment from './components/account/shipment' 
import Quotes from './components/account/quotes'
import AddTcf from './components/addTcf'
import AddPricebook from './components/pricebook/addPricebook'
import AddRecord from './components/accounts/addRecord'
import NewAccount from './components/accounts/newAccount'
import AccountsList from './components/accounts/accounts'
import AccountViewPage from './components/accounts/accountViewPage'
import AddContacts from './components/contact/addContacts';
import ContactLists from './components/contact/contactLists';
import PriceBooklist from './components/pricebook/priceBooklist'
import AddRwoodusers from './components/rwoodusers/addRwoodusers'
import UserList from './components/rwoodusers/userList'
import AddRwoodCompany from './components/rwoodCompany/addRwoodcompany'
import RwoodCompanyLists from './components/rwoodCompany/rwoodCompanyLists'
import AddPrice from './components/price/addPrice'
import UpdatePriceBook from './components/pricebook/updatePricebook'
import PriceLists from './components/price/priceLists'
import AddCotract from './components/contract/addCotract'
import ContractList from './components/contract/contarctList'
import AddOpportunitys from './components/opportunity/addOpportunitys'
import AddRecords from './components/opportunity/addRecords'
import AddQuotes from './components/opportunity/addQuotes'
import OpportunityDetails from './components/opportunity/opportunityDetails'
import OppourtunityList from './components/opportunity/oppourtunityList'
import OpportunityShipmentDetail from './components/opportunity/opportunityShipmentDetail'
import TcfList from './components/tcf/tcfList'
import AddBank from './components/bank/addBank'
import BankLists from './components/bank/BankLists'
import AddoppShippment  from './components/opportunity/addoppShippment'
import ViewOpportunity  from './components/opportunity/viewOpportunity'
import OppShipmentLists from './components/opportunity/oppShipmentList'
import ContractShippment from './components/shippment/contractShippment'
import ContractShippmentList from './components/shippment/contractShippmentList'
import NewProduct from './components/productMaster/addProductMaster'
import ContactViewPage from './components/contact/contactViewPage'
import { AES, enc } from "crypto-js";

import {
  BrowserRouter,
  Routes,
  Route,
  Navigate,
  useLocation,

} from "react-router-dom";
import AuthProvider from "./components/AuthProvider";
import $ from 'jquery'

 

function App() {
  
  const isAuthenticated = localStorage.getItem("access_token");
  const location = useLocation();
 
  console.log(isAuthenticated)
  return ( 
    <AuthProvider> 
    <Routes>
        <Route
          
          path="/"
          element={isAuthenticated ? <Dashboard /> : <Login />}
          isAuthenticated={isAuthenticated}
        />
        <Route
          path="/login"
          isAuthenticated={isAuthenticated}
          element={
            isAuthenticated ? (
              <Navigate
                to={{
                  pathname: location.state?.from || "/",
                  state: { from: location.pathname },
                }}
              />
            ) : (
              <Login/>
            )
          }
        />
        
      <Route
        
        path="/accounts/:id"
        element={isAuthenticated ? <AccountViewPage/> : <Login />}
        isAuthenticated={isAuthenticated}
      />  
      <Route
        
        path="/accounts/accounts-list"
        element={isAuthenticated ? <AccountsList/> : <Login />}
        isAuthenticated={isAuthenticated}
      /> 
   
       
    </Routes> 
    </AuthProvider>
  );
}

export default App;

问题排查与修复方案

  • 缺失BrowserRouter包裹:React Router v6要求所有路由逻辑必须在BrowserRouter组件内部运行。你的App.js导入了BrowserRouter但未使用,导致线上环境无法处理客户端路由,触发硬导航。修复时将Routes包裹在BrowserRouter中:

    function App() {
      const isAuthenticated = localStorage.getItem("access_token");
      const location = useLocation();
    
      return ( 
        <AuthProvider> 
          <BrowserRouter>
            <Routes>
              {/* 原有路由配置 */}
            </Routes>
          </BrowserRouter>
        </AuthProvider>
      );
    }
    
  • 优化Link路径写法:原路径拼接"/accounts"+"/"+x.id易出错,改用模板字符串更可靠:

    <Link to={`/accounts/${x.id}`}><AiFillDiff/></Link>
    
  • 服务器SPA路由配置:线上服务器需配置支持SPA路由,避免刷新子路由时返回404。以Nginx为例,添加如下配置:

    location / {
      try_files $uri $uri/ /index.html;
    }
    
  • useLocation使用限制:useLocation钩子只能在BrowserRouter包裹的组件内使用,修复后可正常获取路由状态。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 15:32:34