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

Next.js中使用Server Action调用API失败问题求助

Next.js登录页Server Action调用API问题排查与修复

问题1:Server Action传递报错

原因

Login组件中定义的callAPI是客户端异步函数,将其作为form的action属性传递时,违反了Next.js规则:客户端组件不能直接传递未标记为use server的函数给表单action。即便signInUser标记了use server,但包裹它的callAPI是客户端函数,依然会触发报错。

修改方案

直接将signInUser作为表单的action,并修改signInUser以接收表单提交的FormData:

  1. 更新action.ts,让signInUser处理FormData:
"use server";
import { callSignInUser } from "@/lib/server";

export async function signInUser(formData: FormData) {
  const email = formData.get("email") as string;
  const password = formData.get("password") as string;
  
  if (!email || !password) {
    return returnError(new Error("邮箱或密码不能为空"));
  }
  
  const res = await callSignInUser(email, password);
  return res;
}
  1. 修改Login组件,移除callAPI,直接绑定signInUser到表单action,并给输入框添加name属性:
import Image from "next/image";
import React from "react";
import lady from "../../../public/landing-girl.svg";
import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
import Link from "next/link";
import { signInUser } from "../actions/action";

export default function Login() {
  return (
    <div className="flex flex-1 flex-col justify-center items-center">
      <Image
        src={lady}
        alt="lady"
        fill={true}
        placeholder="empty"
        priority={false}
        style={{ objectFit: "cover" }}
      />
      <div className="w-screen h-screen bg-black/20 z-10" />
      <div className="w-fit min-w-[500px] h-auto bg-[#F2F2F2]/95 z-20 absolute rounded-lg items-center flex flex-1 px-10 py-5 flex-col">
        <span className="text-primary text-3xl font-semibold">Login</span>
        <span className="text-text-primary mt-3">
          Welcome back! Please enter your details.
        </span>
        <form action={signInUser} className="mt-5 w-full">
          <Input label="Email Id" placeholder="Enter your email" name="email"></Input>
          <Input label="Password" placeholder="Enter your password" name="password"></Input>
          <Button className="w-full" type="submit">
            Sign In
          </Button>
        </form>

        <span className="mt-5 text-text-primary text-sm">
          {"Don't have account? "}
          <Link href="/signup">
            <span className="text-primary font-semibold">Sign Up</span>
          </Link>
        </span>
      </div>
    </div>
  );
}

问题2:网络请求指向localhost而非配置地址

原因

  1. 问题1未解决时,表单执行默认提交行为,直接POST到当前域名(localhost:3000),而非调用Server Action。
  2. fetch请求缺少Content-Type头,服务器无法正确解析JSON请求体;同时API地址拼接时可能出现双斜杠,导致请求地址错误。

修改方案

  1. 确保问题1已修复,Server Action正常执行(此时API请求在服务器端发起,浏览器网络面板不会显示该请求,只会看到Next.js的Server Action请求)。
  2. 更新server.ts,添加请求头并修正地址拼接:
import { isOKResponse, returnError, returnSuccess } from "@/types";
import { createAPIEndpoint } from ".";

export const callSignInUser = async (email: string, password: string) => {
  const json = {
    email: email,
    password: password,
  };
  const response = await fetch(createAPIEndpoint("v1/auth/jwt/create/"), {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
    },
    body: JSON.stringify(json),
  });
  try {
    const data = await response.json();
    if (isOKResponse(response)) {
      return returnSuccess<{}>(data);
    }
  } catch (err) {
    console.error("登录API请求失败:", err);
  }

  return returnError(new Error("登录失败,请稍后重试"));
};
  1. 更新index.ts的地址拼接逻辑,避免双斜杠:
export const API_BASE_URL = "http://xxxxxx/api/";

export const createAPIEndpoint = (path: string) => {
  const cleanPath = path.startsWith("/") ? path.slice(1) : path;
  return `${API_BASE_URL}${cleanPath}`;
};

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 21:35:56