我最近从 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>
);
}
到目前为止我已经尝试过以下方法:
Bearer fake-token-12312312
中(这是有效的),但这违反了DRY原则,而且我有超过100个API函数。axiosInstance.ts
和 staffAPIServices.ts
转换为客户端组件('use client'
)。这不起作用!Prevent client components from being async functions.
axiosInstance.ts
和 staffAPIServices.ts
不是 React 组件,因此添加 'use client'
不会执行任何操作。您需要使使用这些函数的组件成为客户端而不是函数本身。
如果这些组件是客户端,并且您检查了它是否在浏览器环境中运行(放置一些
console.log
并查看它是否打印到终端或浏览器控制台),您可以检查 cookie 本身:
Cookie 可以设置 HttpOnly 属性,在这种情况下,您无法在客户端访问它们。您可以在 Chrome 开发工具的应用程序选项卡上进行检查:
我找到了解决方案。通过将
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>
);
}