Next.js API始终返回HTML而非JSON,登出功能报错求助
问题:NextAuth v5 + Next.js 14 登出功能实现优化
环境信息
- NextAuth版本:v5.0.0-beta.4
- Next.js版本:^14.0.4
当前代码与问题
侧边栏组件(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(); // 报错行 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> Artworks </Nav.Link> </Nav.Item> <Nav.Item className={styles.navItem}> <Nav.Link eventKey="users"> <i className="bi bi-people"></i> 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>; }
API路由(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' }, // }); }
错误信息
SyntaxError: Unexpected token '<', "<!DOCTYPE "... is not valid JSON
尝试过的方案与问题
- 更新1:改用
NextResponse返回JSON,但直接进入catch块,原因未知。 - 更新2:尝试在组件内直接调用
signOut,但报错:import { signOut } from '../../auth'; const handleSignOut = async () => { "use server" try { await signOut({ redirectTo: '/' }); } catch (error) { console.error(error); } }; - 更新3:通过单独的
actions.ts实现Server Actions,可行但希望代码更简洁:
组件调用:// actions.ts export async function handleSignOutServer() { await signOut(); }<Button variant="outline-danger" onClick={() => handleSignOutServer()}>
最优解决方案
方案1:组件内直接使用Server Action(最简洁)
无需单独创建actions.ts,直接在组件内定义带"use server"标记的异步函数:
import { signOut } from '../../auth'; // ... const handleSignOut = async () => { "use server"; await signOut({ redirectTo: '/' }); };
按钮绑定:
<Button variant="outline-danger" onClick={handleSignOut}> <i className="bi bi-power"></i> Sign Out </Button>
说明:Next.js 14中,组件内的异步函数加上"use server"即可成为Server Action,signOut会自动处理会话清除并跳转到指定页面,无需手动调用router.push。
方案2:修复API路由(若坚持使用API路由)
原API路由错误是混用了Pages Router的NextApiRequest/NextApiResponse类型,App Router的API路由应使用正确类型:
import { NextResponse } from "next/server"; import { signOut } from '../../../../auth'; export async function POST() { await signOut({ redirectTo: '/' }); return NextResponse.json({ message: 'Signed out' }, { status: 200 }); }
前端调用简化:
const handleSignOut = async () => { try { await fetch('/api/signout', { method: 'POST' }); } catch (error) { console.error(error); } };
内容的提问来源于stack exchange,提问作者Franva
相关产品推荐
相关产品推荐

