部署在Azure Web App的React应用商品页刷新空白问题求助
问题:React应用部署Azure Web App Service后刷新异常
问题现象
- 初始部署后,登录页可正常渲染,但刷新页面时显示错误:
The resource you are looking for has been removed, had its name changed, or is temporarily unavailable.
- 添加web.config文件后多数功能恢复正常,但商品页仍存在异常:点击进入商品页可正常渲染,刷新后页面变为空白,且页面logo不显示、头部导航菜单无法点击。控制台显示静态资源(如图片、样式文件)出现404错误,原因是资源路径解析错误。
相关代码
index.js
import React, { useState, useEffect } from 'react'; import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom'; import ReactDOM from 'react-dom/client'; import Header from './header.js'; import Product from './product.js'; import MainPage from './main.js'; import Cart from './cart.js'; import Login from './login.js'; import Admin from './adminDashboard.js'; import { getUserDataFromToken } from './authService'; // 检查用户是否已认证 function isAuthenticated() { const token = localStorage.getItem('userToken'); if (token) { const payload = JSON.parse(atob(token.split('.')[1])); // 检查token是否过期 return payload.exp > Date.now() / 1000; } return false; } // 保护路由组件 function PrivateRoute({ children }) { return isAuthenticated() ? children : <Navigate to="/login" />; } function App() { const [user, setUser] = useState(null); useEffect(() => { const userData = getUserDataFromToken(); if (userData) { setUser(userData.email); } }, []); return ( <BrowserRouter> <div> <Routes> <Route index element={<PrivateRoute><MainPage/></PrivateRoute>} /> <Route path="/product/:productId" element={<PrivateRoute><Product product={6}/></PrivateRoute>} /> <Route path="" element={<PrivateRoute><Cart /></PrivateRoute>} /> <Route path="/admin" element={<Admin />} /> <Route path="/login" element={<Login />} /> </Routes> </div> </BrowserRouter> ); } const root = ReactDOM.createRoot(document.getElementById('root')); root.render(<App />);
product.jsx
import { useState, useEffect } from 'react'; import Header from './header.js'; import ProductImages from './ProductImages.js'; import ProductDetails from './ProductDetails.js'; import Comments from './Comments.js'; import AddReview from './AddReview.js'; import styles from './product.module.css'; function App() { let productID = window.location.pathname.split('/')[window.location.pathname.split('/').length-1]; var [CurrentProduct, setProduct] = useState([]); var [loading, setLoading] = useState(true); useEffect(() => { const url = "https://myapi.net/Product/FindProduct/" + productID; fetch(url) .then((response) => response.json()) .then((data) => setProduct(data)); console.log("GETTING DATA FROM SERVER"); setLoading(false); }, [loading]); console.log(CurrentProduct); if (loading) { return <p>Loading...</p>; } if (!loading && CurrentProduct.id > 0) { return ( <div className={styles.productPage}> <Header /> <div className={styles.fullPage}> <ProductImages product={CurrentProduct} /> <ProductDetails product={CurrentProduct} /> <Comments product={CurrentProduct} /> <AddReview product={CurrentProduct} setLoading={setLoading} /> </div> </div> ); } } export default App;
解决建议
- 修正web.config重写规则:确保静态资源不被重定向,所有路由请求都指向index.html。替换为以下配置:
<?xml version="1.0" encoding="UTF-8"?> <configuration> <system.webServer> <rewrite> <rules> <!-- 静态资源直接返回,跳过重写 --> <rule name="Static Files" stopProcessing="true"> <match url="([\S]+[.](html|css|js|png|jpg|jpeg|gif|ico|svg))" /> <action type="None" /> </rule> <!-- 非文件/目录请求重写到index.html --> <rule name="React Routes" stopProcessing="true"> <match url=".*" /> <conditions logicalGrouping="MatchAll"> <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" /> <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" /> </conditions> <action type="Rewrite" url="/index.html" /> </rule> </rules> </rewrite> </system.webServer> </configuration>
- 使用绝对路径引用静态资源:将所有静态资源路径改为根目录开头,比如
/images/logo.png,避免路由变化导致资源路径解析错误。 - 用useParams获取路由参数:替换手动解析路径的方式,避免错误:
import { useParams } from 'react-router-dom'; function Product() { // 组件名改为Product,避免与根App冲突 const { productId } = useParams(); // 后续使用productId作为参数 }
- 修复product.jsx的useEffect逻辑:修正依赖和异步处理,避免无限循环和提前结束加载:
useEffect(() => { setLoading(true); const url = `https://myapi.net/Product/FindProduct/${productId}`; fetch(url) .then(res => res.json()) .then(data => setProduct(data)) .catch(err => console.error('加载商品失败:', err)) .finally(() => setLoading(false)); }, [productId]); // 依赖改为productId,而非loading
- 补充组件默认返回逻辑:在product.jsx末尾添加默认返回,避免页面空白:
// 现有逻辑后添加 return <p>商品不存在或加载失败</p>;
- 修正Cart路由路径:index.js中Cart的路径
path=""会和首页路由冲突,改为path="/cart":
<Route path="/cart" element={<PrivateRoute><Cart /></PrivateRoute>} />
内容的提问来源于stack exchange,提问作者Руслан Василев
相关产品推荐
相关产品推荐

