NextJS 14结合Vercel Blob存储时Server Action异常求助
问题原因与修复方案
核心问题分析
你遇到的页面刷新、URL携带参数且Server Action未执行的问题,主要由以下三点导致:
- 客户端组件未声明
'use client':EditImageModal使用了useRef客户端钩子,但未添加'use client'指令,Next.js会将其视为服务器组件,无法正确绑定Server Action,浏览器退化为默认GET表单提交。 - 表单未指定POST方法:未设置
method="POST",浏览器默认用GET请求提交,导致URL携带表单参数并刷新页面(Server Action仅支持POST请求)。 - 缺少文件上传编码类型:上传文件的表单未设置
enctype="multipart/form-data",无法正确传递文件数据到Server Action。
修复代码
1. 修改EditImageModal.tsx(客户端组件)
添加'use client'指令,同时修正表单属性:
'use client'; // 必须添加,标记为客户端组件 import { Button, Modal, ModalBody, ModalContent, ModalFooter, ModalHeader, } from "@nextui-org/react"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faArrowUpFromBracket } from "@fortawesome/free-solid-svg-icons"; import { useRef } from "react"; export default function EditImageModal(props: { isOpen: boolean; onClose: () => void; serverAction: (formData: FormData) => Promise<void>; // 修正为异步函数类型 }) { const fileInputRef = useRef<HTMLInputElement>(null); const handleClick = () => { if (fileInputRef.current) { fileInputRef.current.click(); } }; return ( <Modal isOpen={props.isOpen} onOpenChange={props.onClose} placement="auto"> {/* 添加POST方法与文件上传编码类型 */} <form action={props.serverAction} method="POST" enctype="multipart/form-data"> <ModalContent> <ModalHeader className="flex flex-col gap-1">Edit Image</ModalHeader> <ModalBody> <div className={`w-full h-64 flex justify-center items-center flex-col gap-4 font-bold hover:cursor-pointer border-2 border-dashed rounded-lg border-black`} onClick={handleClick} > <FontAwesomeIcon icon={faArrowUpFromBracket} size="2x" color="#222222" /> <span>Upload an image</span> <input ref={fileInputRef} type="file" accept="image/*" id="image" name="image" style={{ display: "none" }} /> </div> </ModalBody> <ModalFooter className="flex justify-between"> <Button color="default" variant="bordered" onPress={props.onClose}> Cancel </Button> <Button color="primary" type="submit"> Save </Button> </ModalFooter> </ModalContent> </form> </Modal> ); }
2. 优化EditImageModalWrapper.tsx(服务器组件)
添加错误处理,提升稳定性:
import { put } from "@vercel/blob"; import { revalidatePath } from "next/cache"; import EditImageModal from "./EditImageModal"; export default async function EditImageModalWrapper(props: { isOpen: boolean; onClose: () => void; }) { async function uploadImage(formData: FormData) { "use server"; try { console.log("Server function called"); const imageFile = formData.get("image") as File; if (!imageFile || imageFile.size === 0) { throw new Error("请选择要上传的图片"); } const blob = await put(imageFile.name, imageFile, { access: "public", }); console.log("上传成功:", blob); revalidatePath("/edit"); revalidatePath("/"); } catch (error) { console.error("上传失败:", error); throw new Error("图片上传失败,请重试"); } } return ( <EditImageModal isOpen={props.isOpen} onClose={props.onClose} serverAction={uploadImage} /> ); }
修复说明
'use client'指令:确保组件在客户端运行,正确处理useRef和Server Action的绑定逻辑。method="POST":符合Server Action的请求要求,避免浏览器默认的GET提交行为。enctype="multipart/form-data":是文件上传表单的必填属性,确保文件数据能正确传递到Server Action。- 错误处理:添加异常捕获,便于排查问题并给用户反馈。
内容的提问来源于stack exchange,提问作者Bindo Thorpe
相关产品推荐
相关产品推荐

