Next.js登录后用NextResponse.redirect重定向报JSON.parse错误
登录验证通过后使用NextResponse.redirect()出现JSON解析错误的问题
问题描述
我正在学习NextJS,使用新版App Router构建简易食谱应用,此前所有功能均正常,直到实现登录功能时出现问题:当登录验证通过(使用Prisma和MongoDB,仅检查数据库中是否存在同名用户),尝试用NextResponse.redirect()重定向到首页时,反复出现错误:
Uncaught (in promise) SyntaxError: JSON.parse: unexpected character at line 1 column 1 of the JSON data
若不使用NextResponse.redirect(),仅返回提示“登录成功”的NextResponse.json(),则功能正常。想请教为何登录成功后无法重定向到首页。
相关代码
src/app/api/user/login/route.ts
import { NextResponse } from "next/server"; import prisma from "../../../../utils/prisma"; import bcrypt from "bcryptjs"; export async function POST(request: Request) { const body = await request.json(); const { username, password } = body; const user = await prisma.user.findUnique({ where: { username, }, }); if (!user) { return NextResponse.json( { error: "User " + username + " not found" }, { status: 404 } ); } const match = await bcrypt.compare(password, user.password); if (!match) { return NextResponse.json({ error: "Password incorrect" }, { status: 303 }); } NextResponse.redirect("http://localhost:3000"); }
src/app/auth/page.ts
import React, { useState } from "react"; export default function LoginRegister() { return ( <div className="flex justify-center gap-40 text-2xl mt-40"> <Login /> <Register /> </div> ); } const Login = () => { const [username, setUsername] = useState(""); const [password, setPassword] = useState(""); async function loginHandler() { const data = { username: username, password: password }; await fetch("http://localhost:3000/api/user/login", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(data), }) .then((res) => res.json()) .then((res) => console.log(res)); } return ( <form className="bg-white shadow-md rounded px-8 pt-6 pb-8 mb-4"> <div className="mb-4"> <label className="block text-gray-900 font-bold mb-2" htmlFor="username" > Username </label> <input className="shadow border rounded w-full py-2 px-3 text-gray-900 focus:outline-none focus:shadow-outline" id="username" type="text" placeholder="Username" onChange={(e) => { setUsername(e.target.value); }} required /> </div> <div className="mb-6"> <label className="block text-gray-900 font-bold mb-2" htmlFor="password" > Password </label> <input className="shadow rounded w-full py-2 px-3 text-gray-900 mb-3 focus:outline-none focus:shadow-outline" id="password" type="password" placeholder="******************" onChange={(e) => { setPassword(e.target.value); }} required /> </div> <div className="flex items-center justify-between"> <button className="bg-blue-500 hover:bg-blue-900 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline" type="button" onClick={loginHandler} > Login </button> </div> </form> ); };
问题原因
- 前端解析逻辑冲突:前端
fetch请求后调用了res.json(),但NextResponse.redirect()返回的是303重定向响应,响应体为空,并非JSON格式。前端尝试解析空内容为JSON,必然抛出语法错误。 - API路由未正确返回响应:路由最后一行的
NextResponse.redirect()没有加return,导致函数默认返回200空响应,同样会触发前端的JSON解析错误。 - 状态码使用不规范:密码错误时返回303状态码不符合HTTP规范,应该用401(未授权),避免和重定向状态码混淆。
解决方案
方案一:前端处理重定向(推荐)
API返回登录成功的JSON响应,前端收到后手动跳转,逻辑更清晰可控:
- 修改
route.ts的验证通过及密码错误部分:
// 替换原有的NextResponse.redirect return NextResponse.json({ success: true }, { status: 200 }); // 修正密码错误的状态码 if (!match) { return NextResponse.json({ error: "Password incorrect" }, { status: 401 }); }
- 修改前端
loginHandler:
async function loginHandler() { const data = { username: username, password: password }; await fetch("http://localhost:3000/api/user/login", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(data), }) .then((res) => res.json()) .then((res) => { if (res.success) { window.location.href = "http://localhost:3000"; // 手动跳转首页 } else { alert(res.error); // 展示错误提示 } }) .catch(err => console.error("请求错误:", err)); }
方案二:API直接重定向(适合非AJAX场景)
若坚持用API重定向,需确保前端不解析空响应,同时修正路由的return问题:
- 修改
route.ts:
// 必须加return,用request.url构建目标URL更灵活,指定303状态码 return NextResponse.redirect(new URL("/", request.url), { status: 303 }); // 修正密码错误状态码 if (!match) { return NextResponse.json({ error: "Password incorrect" }, { status: 401 }); }
- 修改前端
loginHandler,跳过JSON解析:
async function loginHandler() { const data = { username: username, password: password }; await fetch("http://localhost:3000/api/user/login", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(data), }) .then((res) => { if (res.status === 303) { window.location.href = "http://localhost:3000"; } else { return res.json().then(err => alert(err.error)); } }) .catch(err => console.error("请求错误:", err)); }
内容的提问来源于stack exchange,提问作者Marc Müller
相关产品推荐
相关产品推荐

