localhost:3000/cart,出现错误为 localhost:3000/api/products/cart 404(未找到)
问题:localhost:3000/cart,出现错误为 localhost:3000/api/products/cart 404(未找到)
我正在开发一个电子商务网站并在其上添加“购物车”路线,但出现以下错误:错误图像本地主机地址为:3000/cart,但错误地址来自:3000/api /products/cart.(我正在使用 express 从:http://localhost:5000/api/products 获取数据)
另外,如果我将地址输入为:“http://localhost:3000/cart/223”,则错误为:
GET http://localhost:3000/cart/api/products/cart 404 (Not Found)
应用程序.js:
function App() {
return (
<Switch>
<Route exact path="/" component={HomePage} />
<Route exact path="/products" component={ProductPage}/ >
<Route path="/:id" component={ProductDetail} />
<Route path="/cart" component={CartPage} />
<Route path="/cart/:id" component={CartPage} />
</Switch>
)
}
export default App;
购物车页面.jsx:
import React, { useEffect } from "react";
import { addToCart } from "../actions/cartActions";
import { useDispatch } from "react-redux";
function CartPage(props) {
const productId = props.match.params.id;
const qty = props.location.search? Number(props.location.search.split("=")[1]): 1;
const dispatch = useDispatch();
useEffect(() => {
if (productId) {
dispatch(addToCart(productId, qty));
}
}, []);
return <div>Hell world!</div>;
}
export default CartPage;
productDetail.jsx:
import React, { useState, useEffect } from "react";
import { useSelector, useDispatch } from "react-redux";
import { detailsProduct } from "../actions/productActions";
function ProductDetail(props) {
const [qty, setQty] = useState(1);
const productDetails = useSelector((state) => state.productDetails);
const { product, loading, error } = productDetails;
const dispatch = useDispatch();
useEffect(() => {
dispatch(detailsProduct(props.match.params.id));
return () => {//};
}, []);
const handleAddToCart = () => {
props.history.push("/cart/" + props.match.params.id + "?qty=" + qty);
};
return ({product.countInStock > 0 && (
<button onClick={handleAddToCart}>
Add to Cart
</button>
)})
http://localhost:5000/api/products:
[
{
name: "Slim Shirt",
category: "Shirts",
image: "/img/d2.png",
price: 60,
brand: "Nike",
rating: 4.5,
numReviews: 10,
_id: "123",
countInStock: 0,
},
{
name: "Best Shirt",
category: "Shirts",
image: "/img/d3.png",
price: 50,
brand: "ads",
rating: 4.6,
numReviews: 12,
_id: "223",
countInStock: 6,
},
....}
server.js:
import express from "express";
import { data } from "./data";
const app = express();
app.get("/api/products/:id", (req, res) => {
const product = data.find((x) => x._id === req.params.id);
if (product) {
res.send(product);
} else {
res.status(404).send({ msg: "Product Not Found!!" });
}
});
app.get("/api/products", (req, res) => {
res.send(data);
});
app.listen(5000, () => {
console.log("server started at http://localhost:5000");
});
包.json:
{
"name": "frontend",
"proxy": "http://127.0.0.1:5000",
"version": "0.1.0",
"private": true,
"dependencies": {
.....}
//store.js:
import { createStore, combineReducers, compose,
applyMiddleware } from "redux";
import {
productDetailsReducer,
productListReducer,
} from "./reducers/productReducers";
import thunk from "redux-thunk";
import { cartReducer } from "./reducers/cartReducers";
const initialState = {};
const reduer = combineReducers({
productList: productListReducer,
productDetails: productDetailsReducer,
cart: cartReducer,
});
const composeEnhancer =
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(
reduer,
initialState,
composeEnhancer(applyMiddleware(thunk))
);
export default store;
//productActions.js:
const listProducts = () => async (dispatch) => {
try {
dispatch({ type: PRODUCT_LIST_REQUEST });
const { data } = await axios.get("api/products");
dispatch({ type: PRODUCT_LIST_SUCCESS, payload: data
});
} catch (error) {
dispatch({ type: PRODUCT_LIST_FAIL, payload:
error.message });
}
};
const detailsProduct = (productId) => async (dispatch) => {
try {
dispatch({ type: PRODUCT_DETAILS_REQUEST, payload:
productId });
const { data } = await axios.get("api/products/" +
productId);
dispatch({ type: PRODUCT_DETAILS_SUCCESS, payload: data
});
} catch (error) {
dispatch({ type: PRODUCT_DETAILS_FAIL, payload:
error.message });
}
};
export { listProducts, detailsProduct };
解答
问题
问题似乎从Switch组件呈现的路由顺序开始。Switch中的路由路径顺序和特殊性很重要。"/:id"路由路径比"/cart"less 特定,"/cart"比"/cart/:id"less 特定,因此它将由Switch匹配和渲染。
<Switch>
<Route exact path="/" component={HomePage} />
<Route exact path="/products" component={ProductPage} />
<Route path="/:id" component={ProductDetail} /> // matches "/cart"
<Route path="/cart" component={CartPage} /> // unreachable route!!
<Route path="/cart/:id" component={CartPage} /> // unreachable route!!
</Switch>
最后两条路线无法到达。当路径为"/cart"并发出无效请求时,会呈现错误的组件。
ProductDetail 调度一个可能意味着使用正确 id 发出获取请求的操作,但"cart"是id值,路径"/cart"与"/:id"路由匹配。
useEffect(() => {
dispatch(detailsProduct(props.match.params.id));
return () => {};
}, []);
解决方案
以路径特异性的相反顺序重新排序路由。在大多数情况下,这样做也完全消除了使用exact属性填充所有路由的需要。
例子:
<Switch>
<Route path="/cart/:id" component={CartPage} />
<Route path="/cart" component={CartPage} />
<Route path="/products" component={ProductPage} />
<Route path="/:id" component={ProductDetail} />
<Route path="/" component={HomePage} />
</Switch>
请注意,"/cart/:id"more 比"/cart"、"/products"和"/:id"更具体,并且"/cart"和"/products"都_more_ 比"/:id"更具体,并且它们_all_ more 具体比上一条路径路径"/"。
另请注意,react-router-dom@5允许Route组件使用path属性的路径数组。请记住,数组中的顺序和特异性仍然很重要。还要记住,数组中的 all 路由应该比下面/之后的路由路径更具体。
例子:
<Switch>
<Route path={["/cart/:id", "/cart"]} component={CartPage} />
<Route path="/products" component={ProductPage} />
<Route path="/:id" component={ProductDetail} />
<Route path="/" component={HomePage} />
</Switch>
API请求
对于请求,请尝试使用绝对路径,即axios.get("/api/products/" + productId),因此不会从"/products"子路由发出请求。您希望 API 请求路径类似于"/api/products/123"而不是"/products/api/products/123"。
例子:
const listProducts = () => async (dispatch) => {
try {
dispatch({ type: PRODUCT_LIST_REQUEST });
const { data } = await axios.get("/api/products");
dispatch({ type: PRODUCT_LIST_SUCCESS, payload: data });
} catch (error) {
dispatch({ type: PRODUCT_LIST_FAIL, payload: error.message });
}
};
const detailsProduct = (productId) => async (dispatch) => {
try {
dispatch({ type: PRODUCT_DETAILS_REQUEST, payload: productId });
const { data } = await axios.get("/api/products/" + productId);
dispatch({ type: PRODUCT_DETAILS_SUCCESS, payload: data });
} catch (error) {
dispatch({ type: PRODUCT_DETAILS_FAIL, payload: error.message });
}
};
export { listProducts, detailsProduct };
更多推荐
所有评论(0)