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

NextJS 13新API目录下RTK Query POST请求触发失败问题排查

NextJS 13中使用RTK Query发起POST请求失败的解决方法

问题场景

尝试在NextJS 13的新API目录下用RTK Query向后端发起POST请求,以下两种触发方式均失败:

// 第一种尝试
const dispatch = useDispatch<AppDispatch>();
dispatch(addMemoria.initiate({firstName, lastName, birthDate: selectedBirthDate, deathDate: selectedDeathDate}));

// 第二种尝试
addMemoria.initiate({firstName, lastName, birthDate: selectedBirthDate, deathDate: selectedDeathDate});

预期是成功发送POST请求并在数据库新增Memoria条目,但出现如下错误:

hydration-error-info.js?32aa:27 An unhandled error occurred processing a request for the endpoint "addMemoria".
In the case of an unhandled error, no tags will be "provided" or "invalidated". Error: Invariant: Method expects to have requestAsyncStorage, none available
    at headers (webpack-internal:///(:3000/e-memoria/app-client)/./node_modules/next/dist/client/components/headers.js:17:15)
    at getServerSession (webpack-internal:///(:3000/e-memoria/app-client)/./node_modules/next-auth/next/index.js:94:35)
    at prepareHeaders (webpack-internal:///(:3000/e-memoria/app-client)/./src/store/strapiApi.ts:23:90)
    at eval (webpack-internal:///(:3000/e-memoria/app-client)/./node_modules/@reduxjs/toolkit/dist/query/rtk-query.esm.js:239:42)
    at step (webpack-internal:///(:3000/e-memoria/app-client)/./node_modules/@reduxjs/toolkit/dist/query/rtk-query.esm.js:44:23)
    at Object.eval [as next] (webpack-internal:///(:3000/e-memoria/app-client)/./node_modules/@reduxjs/toolkit/dist/query/rtk-query.esm.js:25:53)

有效请求参考(HTTP客户端)

用HTTP客户端直接发起POST请求可以成功:

POST http://localhost:1337/api/memorias
Content-Type: application/json
authorization: Bearer ****************************

{
  "data": {
    "firstName": "FirstNAmeTest",
    "lastName": "LAstNameTest",
    "birthDate": "2021-09-01",
    "deathDate": "2021-09-02"
  }
}

当前配置代码

RTK Store配置

export const store = configureStore({
  reducer: {
    strapiApi: strapiApi.reducer,
  },
  middleware(getDefaultMiddleware) {
    return getDefaultMiddleware().concat(strapiApi.middleware);
  },
});

export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;

API端点配置(GET请求已正常授权)

const baseQuery = fetchBaseQuery({
  baseUrl: process.env.STRAPI_API_URL + '/api/', //"http://localhost:3000/api/",
  prepareHeaders: async (headers, { getState }) => {
    const session : any = await getServerSession(authOptions);
    // 如果状态中有token,就添加到请求头
    if (session) {
      headers.set('authorization', `Bearer ${session?.jwt}`)
    }
    headers.set('cache', 'no-store');
    headers.set('Cache-control', 'no-store, max-age=0');

    return headers
  },
})

export const strapiApi = createApi({
  reducerPath: "strapiApi",
  baseQuery: baseQuery,
  tagTypes: ["Memoria", "bla"],
  endpoints: (builder) => ({
    getAllMemorias: builder.query<{ results: Array<{ name: string }> }, void>({
      query: () => `memorias`,
      providesTags: ['bla'],

    }),
    addMemoria: builder.mutation<Memoria, Partial<Memoria>>({
      query: (body: Partial<Memoria>) => ({
        url: `memorias`,
        method: 'POST',
        body: createStrapiPOSTBody(body),
      }),
      invalidatesTags: [{ type: 'Memoria', id: 'LIST' }],
    }),
});

export const { getAllMemorias, addMemoria } = strapiApi.endpoints;

解决方法

1. 错误根源:客户端调用了服务器端方法

错误提示的requestAsyncStorage不可用,是因为你在客户端组件的prepareHeaders里调用了getServerSession——这个NextAuth方法只能在服务器组件、API路由或Server Actions中运行,不能在客户端环境执行。

2. 修改prepareHeaders逻辑,区分环境

需要拆分服务器端和客户端的token获取逻辑:

  • 服务器端:继续用getServerSession获取会话
  • 客户端:通过useSession(来自next-auth/react)获取token,并存入Redux状态后,从getState读取

修改后的baseQuery:

const baseQuery = fetchBaseQuery({
  baseUrl: process.env.STRAPI_API_URL + '/api/',
  prepareHeaders: async (headers, { getState }) => {
    const rootState = getState() as RootState;
    // 从Redux状态读取客户端token(需提前通过useSession存入)
    const clientToken = rootState.auth?.jwt;

    // 服务器端环境
    if (typeof window === 'undefined') {
      const session = await getServerSession(authOptions);
      if (session) {
        headers.set('authorization', `Bearer ${session.jwt}`);
      }
    } 
    // 客户端环境,且有token时设置
    else if (clientToken) {
      headers.set('authorization', `Bearer ${clientToken}`);
    }

    headers.set('cache', 'no-store');
    headers.set('Cache-control', 'no-store, max-age=0');
    return headers;
  },
});

3. 正确触发RTK Query Mutation的方式

不要手动用initiate+dispatch,RTK Query会自动为每个mutation生成对应的钩子(命名规则:use[EndpointName]Mutation),这是客户端组件触发mutation的标准方式,还会自动处理loading/error状态:

'use client';
import { useAddMemoriaMutation } from '@/src/store/strapiApi';

// 在客户端组件内使用
const AddMemoriaForm = () => {
  // 获取mutation方法和状态
  const [addMemoria, { isLoading, error }] = useAddMemoriaMutation();

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    try {
      // 调用mutation并处理结果
      await addMemoria({
        firstName,
        lastName,
        birthDate: selectedBirthDate,
        deathDate: selectedDeathDate
      }).unwrap();
      // 请求成功后的操作,比如重置表单、提示成功
    } catch (err) {
      console.error('添加Memoria失败:', err);
    }
  };

  return (
    <form onSubmit={handleSubmit}>
      {/* 表单内容 */}
      <button type="submit" disabled={isLoading}>
        {isLoading ? '提交中...' : '添加'}
      </button>
      {error && <p className="text-red-500">添加失败,请重试</p>}
    </form>
  );
};

export default AddMemoriaForm;

补充说明

  • 确保你的组件是客户端组件(在NextJS 13中需要添加'use client'指令在文件顶部)
  • 如果还没有Redux的auth slice存储token,可以在客户端组件中用useSession获取后,通过dispatch存入store,或者直接在mutation的query方法中手动设置headers(临时可用,但推荐存入Redux统一管理)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 12:04:58