您好,我正在尝试实现注销逻辑,我的会话令牌存储在 cookie 中,如果令牌不再有效,我想清除它。但 next.js 不允许我这样做,即使他们的文档说我可以通过服务器操作更新 cookie。我觉得我调用服务器操作的方式很可能是问题所在,如果是这样,你能提供更好的方法帮助吗?
这对我来说有点困惑,欢迎所有评论。
import React from 'react';
import { gql } from '@urql/core';
import { cookies } from 'next/headers';
import { getClient } from '../actions';
import { redirect } from 'next/navigation';
const PokemonsQuery = gql`
query Me {
me {
id
username
roles
createdAt
updatedAt
}
}
`;
export default async function Home() {
const result = await getClient().query(PokemonsQuery, {}).toPromise();
async function logout() {
'use server'
// remove cookie
cookies().delete('access_token');
// redirect to login page
redirect('/login');
}
// if any issue happens then logout
if(result.error && result.error.networkError){
await logout();
}
return (
<main>
<h1>This is rendered as part of an RSC</h1>
<ul>
<div>
<p>id: {result.data.me.id}</p>
<p>username: {result.data.me.username}</p>
<p>roles: {result.data.me.roles.join(', ')}</p>
<p>createdAt: {result.data.me.createdAt}</p>
<p>updatedAt: {result.data.me.updatedAt}</p>
</div>
</ul>
</main>
);
}
错误:
Error: Cookies can only be modified in a Server Action or Route Handler. Read more: https://nextjs.org/docs/app/api-reference/functions/cookies#cookiessetname-value-options
at $$ACTION_0 (./src/app/server/page.tsx:125:67)
at Home (./src/app/server/page.tsx:41:15)
您遇到的错误是因为您尝试在 Next.js 中的服务器操作或路由处理程序之外修改 cookie。
但是,用于删除访问令牌的 cookies().delete() 调用超出了 React Server 组件中 cookie 修改的允许范围。
在带有 App Router 的 Next.js 13+ 中,只能在服务器操作或路由处理程序中设置、修改或删除 cookie。
并且您尝试删除异步函数中的 cookie,您需要通过在注销函数顶部添加“使用服务器”来确保该函数被识别为服务器操作。
但是,你的代码已经有“使用服务器”。
我重写了您的代码,将注销正确定义为服务器操作,并修复了处理 GraphQL 查询结果和错误的方式。
import React from 'react';
import { gql } from '@urql/core';
import { cookies } from 'next/headers';
import { getClient } from '../actions';
import { redirect } from 'next/navigation';
// GraphQL query to get user information
const MeQuery = gql`
query Me {
me {
id
username
roles
createdAt
updatedAt
}
}
`;
// Define the logout function as a Server Action
export async function logout() {
'use server';
// Delete the cookie
cookies().delete('access_token');
// Redirect the user to the login page
redirect('/login');
}
export default async function Home() {
// Fetch the user data via GraphQL query
const result = await getClient().query(MeQuery, {}).toPromise();
// Handle network errors by logging the user out
if (result.error && result.error.networkError) {
await logout();
}
// Ensure data is available before rendering
if (!result.data?.me) {
return <p>Loading...</p>;
}
return (
<main>
<h1>This is rendered as part of an RSC</h1>
<div>
<p>id: {result.data.me.id}</p>
<p>username: {result.data.me.username}</p>
<p>roles: {result.data.me.roles.join(', ')}</p>
<p>createdAt: {result.data.me.createdAt}</p>
<p>updatedAt: {result.data.me.updatedAt}</p>
</div>
</main>
);
}