删除缓存后MERN项目服务器仍返回304状态码(RTK Query场景)
问题:MERN项目中RTK Query请求返回304状态码,Postman请求返回200
我在开发MERN项目,使用RTK Query处理请求与缓存。从React发起请求时,服务器控制台持续返回304状态码,但通过Postman请求同一接口则返回200。我尝试删除浏览器缓存、本地存储及Cookie,问题仍未解决,服务器端始终显示该状态码。

相关代码
基础空服务(emptySlice.js)
import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react"; import { baseUrl } from "../utils/base_url"; export const emptySlice = createApi({ reducerPath: "api", baseQuery: fetchBaseQuery({ baseUrl: `${baseUrl}/api/` }), tagTypes: ["Serviceman"], endpoints: (build) => ({}), });
servicemenSlice.js
import { emptySlice } from "./emptySlice"; export const serviceMenSlice = emptySlice.injectEndpoints({ endpoints: (build) => ({ getServiceMen: build.query({ query: () => "serviceman", providesTags: ["Serviceman"], }), }), }); export const { useGetServiceMenQuery } = serviceMenSlice;
index.js
import React from "react"; import ReactDOM from "react-dom/client"; import "./index.css"; import App from "./App"; import reportWebVitals from "./reportWebVitals"; import { BrowserRouter } from "react-router-dom"; import { ApiProvider } from "@reduxjs/toolkit/dist/query/react"; import { emptySlice } from "./services/emptySlice"; const root = ReactDOM.createRoot(document.getElementById("root")); root.render( <BrowserRouter> <ApiProvider api={emptySlice}> <App /> </ApiProvider> </BrowserRouter> ); // If you want to start measuring performance in your app, pass a function reportWebVitals();
Landing.jsx(问题触发组件)
import React, { useEffect, useState } from "react"; import PropTypes from "prop-types"; import Header from "../../components/Header/Header"; import ServiceSearchBar from "../../components/ServiceSearchBar/ServiceSearchBar"; import ServiceCategoryList from "../../components/ServiceCategoryList/ServiceCategoryList"; import { useDispatch, useSelector } from "react-redux"; import { getServices } from "../../features/service/serviceSlice"; import MainContentWrapper from "../../components/MainContentWrapper/MainContentWrapper"; import { getAllServiceMen } from "../../features/serviceMan/serviceManSlice"; import ServiceMan from "../../components/ServiceMan/ServiceMan"; import Footer from "../../components/Footer/Footer"; import PageWrapper from "../../components/PageWrapper/PageWrapper"; import Loading from "../../components/Loading/Loading"; import Badge from "../../components/Badge/Badge"; import { useGetServiceMenQuery } from "../../services/servicemenSlice"; import { useGetServicesQuery } from "../../services/serviceSlice"; const Landing = () => { const { data: serviceMen, isLoading, isFetching, isError, error, } = useGetServiceMenQuery(); const { data: services, isLoading: isLoadingServices, isFetching: isFetchingServices, isError: isErrorServices, } = useGetServicesQuery(); const [activeServiceMen, setActiveServiceMen] = useState([]); if (isLoading || isFetching) { return <Loading />; } if (isError) { return <h1>{error}</h1>; } const serviceMenList = serviceMen.map((serviceMan) => ( <ServiceMan key={serviceMan._id} serviceMan={serviceMan} /> )); const activeServices = services.filter((service) => service.active); return ( <PageWrapper> <Header /> <MainContentWrapper> <ServiceSearchBar /> <section className="grid grid-col lg:grid-cols-4 w-full gap-5 items-start mb-10"> <div className="flex col-span-full lg:col-span-1 flex-col gap-2"> <Badge text="Services" number={activeServices.length} /> <ServiceCategoryList services={activeServices} /> </div> <div className="col-span-full lg:col-span-3 w-full justify-center"> <Badge text="Service Men" number={activeServiceMen.length} /> <div className="flex flex-col gap-4 mt-5 pr-6"> {activeServiceMen.length > 0 ? ( { serviceMenList } ) : ( <div className="flex justify-center items-center"> <p className="text-black">No service man yet</p> </div> )} </div> </div> </section> </MainContentWrapper> <Footer /> </PageWrapper> ); }; Landing.propTypes = {}; export default Landing;
解决方案
1. 全局禁用浏览器缓存(修改fetchBaseQuery配置)
RTK Query的fetchBaseQuery默认遵循浏览器缓存策略,会触发协商缓存返回304。可以通过添加请求头强制浏览器跳过缓存:
修改emptySlice.js中的fetchBaseQuery配置:
export const emptySlice = createApi({ reducerPath: "api", baseQuery: fetchBaseQuery({ baseUrl: `${baseUrl}/api/`, headers: { 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0' } }), tagTypes: ["Serviceman"], endpoints: (build) => ({}), });
2. 针对单个查询强制刷新
如果不需要全局禁用缓存,可以给特定查询添加强制刷新配置,或者在组件调用时指定刷新规则:
方式一:在查询定义中配置
修改servicemenSlice.js的getServiceMen:
getServiceMen: build.query({ query: () => "serviceman", providesTags: ["Serviceman"], extraOptions: { forceRefetch: true // 强制每次请求都从服务器拉取最新数据 } }),
方式二:在组件调用时传入参数
修改Landing.jsx中的查询调用:
const { data: serviceMen, isLoading, isFetching, isError, error, } = useGetServiceMenQuery(undefined, { refetchOnMountOrArgChange: true // 组件挂载或参数变化时自动刷新 });
3. 检查服务器端缓存配置
304状态码由服务器返回,说明后端可能设置了缓存头。需要检查Express等后端框架的缓存配置,确保动态接口不被缓存:
例如在Express接口中添加禁用缓存的响应头:
app.get('/api/serviceman', (req, res) => { // 禁用缓存 res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate'); res.setHeader('Pragma', 'no-cache'); res.setHeader('Expires', '0'); // 业务逻辑 res.json(serviceMenData); });
4. 手动触发RTK Query缓存刷新
如果需要在特定时机(比如数据更新后)刷新缓存,可以调用refetch方法:
const { data: serviceMen, refetch } = useGetServiceMenQuery(); // 在需要刷新的时机调用,比如组件挂载时 useEffect(() => { refetch(); }, []);
内容的提问来源于stack exchange,提问作者Bello Shehu
相关产品推荐
相关产品推荐

