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

无需从Server Components传递Cookie至API函数的实现方案

解决Next.js Server Components无需手动传递SessionId到API函数的问题

问题场景

目前在Next.js Server Components中,我可以通过next/headers的cookies()获取SessionId,再手动传递给API函数,以此让后端请求携带Cookie避免401错误。但每次调用API都要传SessionId太繁琐,尝试直接在api.ts里调用cookies()时,会触发以下错误:

Invariant: cookies() expects to have requestAsyncStorage, none available.

原因是Next.js的cookies()只能在有请求上下文的环境(比如Server Components、Server Actions、Route Handlers)中使用,而api.ts作为独立工具模块没有这个上下文,所以无法直接调用。

可行解决方案

方案1:创建带上下文的API实例工厂

不要定义全局axios实例,而是写一个工厂函数,接收SessionId生成已携带Cookie的API实例,在Server Components中初始化一次后,所有API调用复用该实例即可。

api.ts 代码修改:

import axios from 'axios';

// 工厂函数:根据SessionId创建API实例
export const createApiInstance = (sessionId: string) => {
  return axios.create({
    baseURL: getBaseUrl(),
    headers: {
      Accept: 'application/hal+json',
      'Content-Type': 'application/json',
      'Accept-Version': '0.24.0.0',
      Cookie: `SESSIONID.DEV=${sessionId}`,
    },
    withCredentials: true,
  });
};

// 通用请求函数,依赖传入的API实例
export const fetchData = async (id: string, apiInstance: ReturnType<typeof createApiInstance>) => {
  try {
    const response = await apiInstance.get(`/data/${id}`);
    return response.data;
  } catch (error) {
    console.error('Error fetching current asset', error);
    throw error;
  }
};

Server Components 中使用:

import { cookies } from 'next/headers';
import { createApiInstance, fetchData } from './api';

const cookieStore = cookies();
const sessionId = cookieStore.get('SESSIONID.DEV')?.value;
// 初始化一次API实例(注意处理SessionId为空的情况)
const api = createApiInstance(sessionId!);

const asset = await queryClient.fetchQuery({
  queryKey: ['asset', params.id],
  queryFn: () => fetchData(params.id, api),
});

console.log('Fetched asset:', asset);

方案2:用Server Action封装API调用

把API请求逻辑放到Server Action中,Server Action自带请求上下文,可直接调用cookies()获取SessionId,组件只需调用Action,无需手动传参。

actions.ts 代码:

'use server';

import { cookies } from 'next/headers';
import axios from 'axios';

const api = axios.create({
  baseURL: getBaseUrl(),
  headers: {
    Accept: 'application/hal+json',
    'Content-Type': 'application/json',
    'Accept-Version': '0.24.0.0',
  },
  withCredentials: true,
});

// Server Action:封装数据请求逻辑
export async function fetchDataAction(id: string) {
  const sessionId = cookies().get('SESSIONID.DEV')?.value;
  try {
    const response = await api.get(`/data/${id}`, {
      headers: {
        Cookie: `SESSIONID.DEV=${sessionId}`,
      },
    });
    return response.data;
  } catch (error) {
    console.error('Error fetching current asset', error);
    throw error;
  }
}

Server Components 中使用:

import { fetchDataAction } from './actions';

const asset = await queryClient.fetchQuery({
  queryKey: ['asset', params.id],
  queryFn: () => fetchDataAction(params.id),
});

console.log('Fetched asset:', asset);

方案3:用Route Handler做请求代理

创建Next.js的Route Handler作为中间层,在Handler中获取Cookie并转发请求到后端API,组件直接请求本地API即可,无需处理SessionId。

app/api/data/[id]/route.ts 代码:

import { cookies } from 'next/headers';
import axios from 'axios';
import { NextResponse } from 'next/server';

export async function GET(request: Request, { params }: { params: { id: string } }) {
  const sessionId = cookies().get('SESSIONID.DEV')?.value;
  try {
    const response = await axios.get(`${getBaseUrl()}/data/${params.id}`, {
      headers: {
        Accept: 'application/hal+json',
        'Content-Type': 'application/json',
        'Accept-Version': '0.24.0.0',
        Cookie: `SESSIONID.DEV=${sessionId}`,
      },
      withCredentials: true,
    });
    return NextResponse.json(response.data);
  } catch (error) {
    console.error('Error fetching current asset', error);
    return NextResponse.json({ error: 'Failed to fetch data' }, { status: 500 });
  }
}

Server Components 中使用:

const asset = await queryClient.fetchQuery({
  queryKey: ['asset', params.id],
  queryFn: async () => {
    const res = await fetch(`/api/data/${params.id}`);
    if (!res.ok) throw new Error('Failed to fetch');
    return res.json();
  },
});

console.log('Fetched asset:', asset);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 01:23:17