Nextjs 14 - 无法访问 axiosInstance 和任何 apiService 文件中的 cookie

问题描述 投票:0回答:2

我最近从 React 迁移到 Nextjs,Nextjs 的架构对我来说是不同的并且令人困惑。在我的下一个应用程序中,我尝试通过存储在 cookie 中的令牌来授权 API CRUD。在 axiosInstance 内部,我试图获取令牌,但它正在输出

undefined

axiosInstance.ts

import axios from 'axios';
import Cookies from 'js-cookie';

const axiosInstance = axios.create({
  baseURL: process.env.NEXT_PUBLIC_CLIENT_URL,
  withCredentials: true,
});

axiosInstance.interceptors.request.use((config) => {
  const token = Cookies.get('token');
  if (token) {
    config.headers.Authorization = `Bearer ${token}`;
  }
  return config;
});

export default axiosInstance;

这里是获取人员数据的api函数。

staffAPIServices.ts

import axiosInstance from '../../axios/axiosInstance';
// Get Staff
export const getStaff = async () => {
  try {
    const response = await axiosInstance.get('admin/staff');
    if (response.data.status) {
      return response?.data?.data?.staff;
    }
  } catch (err: unknown) {
    const errorString = err instanceof Error ? err.message : 'Unknown Error';
    return err;
  }
};

为了展示表中的员工数据,我编写了以下代码:

import clsx from 'clsx';
import { getStaff } from '@/app/utils/services/staff/staffAPIServices';


export default async function StaffTable({
  query,
  page,
}: {
  query: string;
  page: number;
}) {

  interface ItemType {
    id: number;
    name: string;
    email: string;
    email_verified_at: string;
    created_at: string;
    updated_at: string;
    deleted_at: string;
  }

  const staff = await getStaff();

  return (
    <div className="mt-6 flow-root">
      <div className="inline-block min-w-full align-middle">
        <div className="rounded-lg bg-gray-50 p-2 md:pt-0">
          <table className="hidden min-w-full text-gray-900 md:table">
            <thead className="rounded-lg text-left text-sm font-normal">
              <tr>
                <th scope="col" className="px-4 py-5 font-medium sm:pl-6">
                  ID
                </th>
                <th scope="col" className="px-3 py-5 font-medium">
                  Name
                </th>
                <th scope="col" className="px-3 py-5 font-medium">
                  Email
                </th>
                <th scope="col" className="px-3 py-5 font-medium">
                  Date
                </th>
                <th scope="col" className="px-2 py-5 font-medium">
                  Status
                </th>
                <th scope="col" className="relative py-3 pl-6 pr-3">
                  <span className="sr-only">Edit</span>
                </th>
              </tr>
            </thead>
            <tbody className="bg-white">
              {Array.isArray(staff) &&
                staff.map((item: ItemType) => (
                  <tr
                    key={item.id}
                    className="w-full border-b py-4 text-sm last-of-type:border-none [&:first-child>td:first-child]:rounded-tl-lg [&:first-child>td:last-child]:rounded-tr-lg [&:last-child>td:first-child]:rounded-bl-lg [&:last-child>td:last-child]:rounded-br-lg"
                  >
                    <td className="whitespace-nowrap py-3 pl-6 pr-3">
                      <p>{item.id}</p>
                    </td>
                    <td className="whitespace-nowrap px-3 py-4">{item.name}</td>
                    <td className="whitespace-nowrap px-3 py-4">
                      {item.email}
                    </td>
                    <td className="whitespace-nowrap px-3 py-4">
                      {item.created_at}
                    </td>
                    <td className="whitespace-nowrap px-3 py-4">
                      <span
                        className={clsx(
                          'flex items-center justify-center rounded-full px-4 py-1',
                          {
                            'bg-red-500 text-white': item.deleted_at === null,
                            'bg-green-500 text-white': item.deleted_at !== null,
                          },
                        )}
                      >
                        {item.deleted_at ? 'Active' : 'Inactive'}
                      </span>
                    </td>
                  </tr>
                ))}
            </tbody>
          </table>
        </div>
      </div>
    </div>
  );
}

到目前为止我已经尝试过以下方法:

  1. 将令牌字符串直接粘贴到
    Bearer fake-token-12312312
    中(这是有效的),但这违反了DRY原则,而且我有超过100个API函数。
  2. axiosInstance.ts
    staffAPIServices.ts
    转换为客户端组件(
    'use client'
    )。这不起作用!
  3. 在另一个 StackOverflow 问题中,有人建议通过转换为客户端组件来在页面内获取 cookie,但接下来是抱怨
    Prevent client components from being async functions.
javascript typescript axios next.js14
2个回答
0
投票

axiosInstance.ts
staffAPIServices.ts
不是 React 组件,因此添加
'use client'
不会执行任何操作。您需要使使用这些函数的组件成为客户端而不是函数本身。

如果这些组件是客户端,并且您检查了它是否在浏览器环境中运行(放置一些

console.log
并查看它是否打印到终端或浏览器控制台),您可以检查 cookie 本身:

Cookie 可以设置 HttpOnly 属性,在这种情况下,您无法在客户端访问它们。您可以在 Chrome 开发工具的应用程序选项卡上进行检查:


0
投票

我找到了解决方案。通过将

StaffTable
转换为客户端组件,API 成功获取存储的令牌 cookie,并返回响应数据。不过,我不知道这是否是专业的Nextjs做法。

'use client';

import { useEffect, useState } from 'react'; import clsx from 'clsx'; import { getStaff } from '@/app/utils/services/staff/staffAPIServices';

export default function StaffTable({   query,   page, }: {   query: string;   page: number; }) {   interface ItemType {
    id: number;
    name: string;
    email: string;
    email_verified_at: string;
    created_at: string;
    updated_at: string;
    deleted_at: string;   }

  const [staff, setStaff] = useState<ItemType[]>([]);   const [loading, setLoading] = useState(true);   const [error, setError] = useState('');

  useEffect(() => {
    const fetchStaff = async () => {
      try {
        const staffData = await getStaff();
        setStaff(staffData);
        setLoading(false);
      } catch (error) {
        setError('Error fetching staff data');
        setLoading(false);
      }
    };

    fetchStaff();   }, []);

  if (loading) {
    return <p>Loading...</p>;   }

  if (error) {
    return <p>{error}</p>;   }

  return (
    <div className="mt-6 flow-root">
      <div className="inline-block min-w-full align-middle">
        <div className="rounded-lg bg-gray-50 p-2 md:pt-0">
          <table className="hidden min-w-full text-gray-900 md:table">
            <thead className="rounded-lg text-left text-sm font-normal">
              <tr>
                <th scope="col" className="px-4 py-5 font-medium sm:pl-6">
                  ID
                </th>
                <th scope="col" className="px-3 py-5 font-medium">
                  Name
                </th>
                <th scope="col" className="px-3 py-5 font-medium">
                  Email
                </th>
                <th scope="col" className="px-3 py-5 font-medium">
                  Date
                </th>
                <th scope="col" className="px-2 py-5 font-medium">
                  Status
                </th>
                <th scope="col" className="relative py-3 pl-6 pr-3">
                  <span className="sr-only">Edit</span>
                </th>
              </tr>
            </thead>
            <tbody className="bg-white">
              {Array.isArray(staff) &&
                staff.map((item: ItemType) => (
                  <tr
                    key={item.id}
                    className="w-full border-b py-4 text-sm last-of-type:border-none [&:first-child>td:first-child]:rounded-tl-lg [&:first-child>td:last-child]:rounded-tr-lg [&:last-child>td:first-child]:rounded-bl-lg [&:last-child>td:last-child]:rounded-br-lg"
                  >
                    <td className="whitespace-nowrap py-3 pl-6 pr-3">
                      <p>{item.id}</p>
                    </td>
                    <td className="whitespace-nowrap px-3 py-4">{item.name}</td>
                    <td className="whitespace-nowrap px-3 py-4">
                      {item.email}
                    </td>
                    <td className="whitespace-nowrap px-3 py-4">
                      {item.created_at}
                    </td>
                    <td className="whitespace-nowrap px-3 py-4">
                      <span
                        className={clsx(
                          'flex items-center justify-center rounded-full px-4 py-1',
                          {
                            'bg-red-500 text-white': item.deleted_at === null,
                            'bg-green-500 text-white': item.deleted_at !== null,
                          },
                        )}
                      >
                        {item.deleted_at ? 'Active' : 'Inactive'}
                      </span>
                    </td>
                  </tr>
                ))}
            </tbody>
          </table>
        </div>
      </div>
    </div>   
); 
}
© www.soinside.com 2019 - 2024. All rights reserved.