You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Next.js 14 App Router调用本地Auth API遇404错误求助

问题:Next.js 13+ App Router API 404错误及Promise作用域问题

核心问题

  • 调用注册API时持续返回404错误
  • 消息监听器的Promise响应超出作用域

现有代码情况

1. API路由文件(app/api/auth/route.js)

import { hashPassword } from "@/app/lib/auth";
import { connectToDatabase } from "../../lib/db";

export async function POST(req, res) {
  const data = req.body;

  const { email, password } = data;

  if (
    !email ||
    !email.includes("@") ||
    !password ||
    password.trim().length < 7
  ) {
    res.status(422).json({
      message:
        "Invalid input - password should also be at least 7 characters long",
    });
  }

  const client = await connectToDatabase();

  const db = client.db();

  const hashedPassword = await hashPassword(password);

  const result = await db.collection("users").insertOne({
    email: email,
    password: hashedPassword,
  });

  res.status(201).json({ message: "Created user!" });
  client.close();
}

2. 前端LoginForm组件(components/LoginForm.js)

"use client";
// components/LoginForm.js
import { useState, useRef } from "react";
import classes from "./login.module.css";

async function createUser(email, password) {
  const response = await fetch("http://localhost:3000/api/auth/route", {
    method: "POST",
    body: JSON.stringify({ email, password }),
    headers: {
      "Content-Type": "application/json",
    },
  });
  const data = await response.json();

  if (!response.ok) {
    throw new Error(data.message || "Something went wrong");
  }

  return data;
}

const LoginForm = () => {
  const emailInputRef = useRef();
  const passwordInputRef = useRef();
  const [isLogin, setIsLogin] = useState(true);

  function switchAuthModeHandler() {
    setIsLogin((prevState) => !prevState);
  }

  async function submitHandler(event) {
    event.preventDefault();

    const enteredEmail = emailInputRef.current.value;
    const enteredPassword = passwordInputRef.current.value;

    //optional: Add validation

    if (isLogin) {
    } else {
      try {
        const result = await createUser(enteredEmail, enteredPassword);
        console.log(result);
      } catch (error) {
        console.log(error);
      }
    }
  }

  return (
    <section className={classes.auth}>
      <h1>{isLogin ? "Login" : "Sign Up"}</h1>
      <form onSubmit={submitHandler}>
        <div className={classes.control}>
          <label htmlFor='email'>Your Email</label>
          <input type='email' id='email' required ref={emailInputRef} />
        </div>

        <div className={classes.control}>
          <label htmlFor='password'>Your Password</label>
          <input
            type='password'
            id='password'
            required
            ref={passwordInputRef}
          />
        </div>
        <div className={classes.actions}>
          <button type='submit'>{isLogin ? "Login" : "Create Account"}</button>
          <button
            type='button'
            className={classes.toggle}
            onClick={switchAuthModeHandler}
          >
            {isLogin ? "Create new account" : "Login with existing account"}
          </button>
        </div>
      </form>
    </section>
  );
};

export default LoginForm;

3. 数据库连接函数(lib/db.js)

import { MongoClient } from "mongodb";
async function connectToDatabase() {
  const client = await MongoClient.connect(
    "mongodb+srv://<username>:<password>@cluster0.<string>.mongodb.net/"
  );
  return client;
}

问题修复步骤

1. 修正API路由路径

Next.js App Router中,app/api/auth/route.js对应的API路径是/api/auth,而非/api/auth/route。修改前端请求URL:

// LoginForm.js中的createUser函数
const response = await fetch("/api/auth", { // 去掉末尾的/route
  method: "POST",
  body: JSON.stringify({ email, password }),
  headers: {
    "Content-Type": "application/json",
  },
});

2. 修复API路由的Next.js 13+语法

App Router的API路由不再使用req, res参数,而是返回NextResponse:

// app/api/auth/route.js
import { hashPassword } from "@/app/lib/auth";
import { connectToDatabase } from "../../lib/db";
import { NextResponse } from "next/server"; // 导入NextResponse

export async function POST(req) { // 只接收req参数
  const data = await req.json(); // 用req.json()替代req.body

  const { email, password } = data;

  if (
    !email ||
    !email.includes("@") ||
    !password ||
    password.trim().length < 7
  ) {
    return NextResponse.json( // 返回NextResponse
      { message: "Invalid input - password should also be at least 7 characters long" },
      { status: 422 }
    );
  }

  const client = await connectToDatabase();

  const db = client.db();

  // 新增:检查用户是否已存在,避免重复创建
  const existingUser = await db.collection("users").findOne({ email });
  if (existingUser) {
    client.close();
    return NextResponse.json(
      { message: "User already exists!" },
      { status: 422 }
    );
  }

  const hashedPassword = await hashPassword(password);

  const result = await db.collection("users").insertOne({
    email: email,
    password: hashedPassword,
  });

  client.close();
  return NextResponse.json( // 返回NextResponse
    { message: "Created user!" },
    { status: 201 }
  );
}

3. 解决Promise作用域问题

确保所有异步操作都正确等待,并且错误被捕获:

  • API路由中,所有await操作都正确使用,每个分支都有明确返回值(避免函数无返回导致的Promise异常)
  • 前端submitHandler中,确保createUser的Promise被正确await,错误被catch处理

4. 数据库连接优化(可选)

为避免频繁创建数据库连接,建议使用连接池或缓存客户端:

// lib/db.js
import { MongoClient } from "mongodb";

let client;
let clientPromise;

if (!process.env.MONGODB_URI) {
  throw new Error("Please add your Mongo URI to .env.local");
}

const uri = process.env.MONGODB_URI;

if (process.env.NODE_ENV === "development") {
  // 开发环境下缓存客户端
  if (!global._mongoClientPromise) {
    client = new MongoClient(uri);
    global._mongoClientPromise = client.connect();
  }
  clientPromise = global._mongoClientPromise;
} else {
  // 生产环境直接创建连接
  client = new MongoClient(uri);
  clientPromise = client.connect();
}

export default clientPromise;

在API路由中修改使用方式:

import clientPromise from "../../lib/db";

// ...
const client = await clientPromise;
const db = client.db();
// ...

验证步骤

  1. 重启Next.js开发服务器
  2. 提交注册表单,检查网络请求是否返回201状态码
  3. 查看MongoDB数据库是否新增用户记录

内容的提问来源于stack exchange,提问作者Jason Rosenthal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 19:23:16