为什么nextjs不允许我从服务器组件中的服务器操作写入cookie

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

您好,我正在尝试实现注销逻辑,我的会话令牌存储在 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)
reactjs next.js web-applications frontend react-server-components
1个回答
0
投票

您遇到的错误是因为您尝试在 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>
    );
}

© www.soinside.com 2019 - 2024. All rights reserved.