Nextjs API总是返回html格式,而不是预期的JSON格式

bwntbbo3  于 12个月前  发布在  其他
关注(0)|答案(1)|浏览(107)

我正在尝试注销用户,我正在使用next-auth@beta(不确定这是否有助于解决我的问题,但我只是在这里包含此信息。
这是我的 Jmeter 板侧边栏组件src\components\ap-sidebar.tsx

import { Button, Nav } from 'react-bootstrap';
import styles from './ap-sidebar.module.css';
import { useRouter } from "next/navigation";

export function Sidebar({ activeTab, setActiveTab }: { activeTab: string, setActiveTab: React.Dispatch<React.SetStateAction<string>>}) {
    const router = useRouter();

    const handleSelect = (selectedTab: string | null, event: React.SyntheticEvent<unknown>) => {
        if (selectedTab) {
            setActiveTab(selectedTab);
        }
    };

    const handleSignOut = async () => {
      try {
        const response = await fetch('/api/signout', { method: 'POST' });
        if (response.status !== 200) {
          console.error("sign out error : " + response.status);
          return;
        }

        const a = await response.json(); // error happens on this  line.
        console.log(a.message);

        router.push('/');
      } catch (error) {
        console.error(error);
      }
    };

    return (
    <Nav variant="pills" className={styles.sidebar} activeKey={activeTab} onSelect={handleSelect}>
      <Nav.Item className={styles.navItem}>
        <Nav.Link eventKey="artworks">
            <i className="bi bi-images"></i> &nbsp;
            Artworks
        </Nav.Link>
      </Nav.Item>

      <Nav.Item className={styles.navItem}>
        <Nav.Link eventKey="users">
            <i className="bi bi-people"></i> &nbsp;
            Users
        </Nav.Link>
      </Nav.Item>

      <div className={styles.spaceHolder}></div>
      
      <Nav.Item className={styles.navItem}>
        <Button variant="outline-danger" onClick={handleSignOut}>
            <i className="bi bi-power"></i> Sign Out
        </Button>
      </Nav.Item>
    </Nav>
  );
}

export function ArtworkManager() {
  return <div style={{width: "100%"}}>Artwork Manager</div>;
}

export function UserManager() {
  return <div style={{width: "100%"}}>User Manager</div>;
}

字符串
src/app/api/signout/route.ts

import { NextApiRequest, NextApiResponse } from 'next';
import { NextRequest, NextResponse } from "next/server";
import { signOut } from '../../../../auth'; 

// export async function POST(req: NextApiRequest, res: NextApiResponse) {
export async function POST(req: NextApiRequest, res: NextApiResponse) {
  await signOut();
  return res.json({ message: 'Signed out' });
  // return res.status(200).json({ message: 'Signed out' });
  // return res.end(JSON.stringify({ message: 'Signed out', status: 200 }));
  // return new Response(JSON.stringify({ message: 'Signed out', status: 200 }), {
  //   headers: { 'Content-Type': 'application/json' },
  // });
}


正如你所看到的,我已经搜索了许多帖子,并尝试了许多不同的方法(注解代码),但错误是如此顽固,总是发生在这行代码:
const a = await response.json();
错误消息:
语法错误:意外的标记“<$”,“<!DOCTYPE“.不是有效的JSON
任何帮助都很感激。

更新1

我现在使用NextResponse在try/catch块中返回json成功消息。但它直接进入catch块。不知道为什么
x1c 0d1x的数据

更新2

我正在使用
“next”:“^14.0.4”,
“next-auth”:“^5.0.0-beta.4”
我最初的想法是做这样的事情:

import { signOut } from '../../auth';
const handleSignOut = async () => {
  "use server"
  try {
    await signOut({ redirectTo: '/' });
  } catch (error) {
    console.error(error);
  }
};


这是auth.ts

import NextAuth from 'next-auth';
import { authConfig } from './auth.config';
import Credentials from 'next-auth/providers/credentials';
import { z } from 'zod';
import { sql } from '@vercel/postgres';
import bcrypt from 'bcryptjs';

 
async function getUser(email: string): Promise<User | undefined> {
      .....
}
 
export const { auth, signIn, signOut } = NextAuth({
    ...authConfig,
    providers: [
      Credentials({
        async authorize(credentials) {

          const parsedCredentials = z
            .object({ email: z.string().email(), password: z.string().min(6) })
            .safeParse(credentials);
   
          if (parsedCredentials.success) {
            const { email, password } = parsedCredentials.data;
            const user = await getUser(email);
            if (!user) return null;
            const passwordsMatch = await bcrypt.compare(password, user.passwordhash);

            if (passwordsMatch) return user;
          }
   
          console.log('Invalid credentials');
          return null;
        },
      }),
    ],
  });


但是当我这样做的时候,我得到了以下错误。


更新3

当在actions.ts内部的服务器端使用signOut()时,正如@AdamBeleko所提到的,它会像设计的那样抛出异常。所以如果我真的想使用try/catch块,那么这就是我如何做到的。
actions.ts

export async function handleSignOutServer(): Promise<boolean> {
  try {
    await signOut();
    return true;
  } catch (error) { 
    if ((error as Error).message === 'NEXT_REDIRECT') return true;
    console.error('An unexpected error happened during sign out:', error);
    throw error;
  }
}


在我的UI组件中:
<Button variant=“outline-danger”onClick={()=>取消SignOut()}>....

const handleSignOut = async () => {
  try {
    const success = await handleSignOutServer();
    if (success === true)
    {
      router.push('/');
    }
  } catch (error) {
    console.error(error);
  }
};


但这似乎过于复杂了。所以为了降低开销的复杂性,我这样做了:
actions.ts

export async function handleSignOutServer() {
  await signOut();
}


在UI组件中:

<Button variant="outline-danger" onClick={() => handleSignOutServer()}>


这样,就没有额外的代码,而且看起来更漂亮。

deikduxw

deikduxw1#

这个问题可能只是你的API路由问题。NextJS 13中的响应是从NextResponse模块解析的,而不是像以前的版本那样从API函数参数解析的。更具体地说,你必须导入并使用NextResponse模块:

import { NextResponse } from "next/server";
import { signOut } from '../../../../auth'; 

export async function POST(req: Request) {
  try {
    await signOut();
    return NextResponse.json({ message: 'Signed out' }, {
        status: 200,
    });
  } catch {
    return NextResponse.json({ message: 'Internal Server Error' }, {
      status: 500,
    });
  }
}

字符串
确保signout函数不是客户端函数(可能是API请求)并因此可以在服务器端代码中运行也很重要。

**更新:**您遇到的错误与auth的signout函数自动重定向有关,参见:Next 13.4 Error: NEXT_REDIRECT in API routes

要解决此问题,请尝试将重定向选项设置为false:

import { NextResponse } from "next/server";
import { signOut } from '../../../../auth'; 

export async function POST(req: Request) {
  try {
    // set redirect to false
    await signOut({ redirect: false });
    return NextResponse.json({ message: 'Signed out' }, {
        status: 200,
    });
  } catch {
    return NextResponse.json({ message: 'Internal Server Error' }, {
      status: 500,
    });
  }
}


或者,根据文档,直接在客户端的“登录SignOut”函数中使用signout函数,并使用您想要重定向到的路径设置redirectTo选项:

const handleSignOut = async () => {
      "use server"
      try {
        await signOut({ redirectTo: '/' });
      } catch (error) {
        console.error(error);
      }
    };


参见:https://authjs.dev/reference/nextjs#signout

更新2要在客户端组件中使用服务器函数,请创建一个仅包含服务器函数的文件:

// app/actions.js
'use server'

import { signOut } from './path/to/auth';
 
export async function handleSignout() {
  try {
    await signOut({ redirect: false });
  } catch (error) {
    console.error(error);
  }
}


稍后,在客户端组件中导入该组件:

import { handleSignout } from '@/app/actions'


现在可以在代码中使用该函数了。请确保在客户端组件代码中删除了该函数的Signout回调。
参见:https://nextjs.org/docs/app/building-your-application/data-fetching/server-actions-and-mutations#client-components

相关问题