Next.js 14:使用 formData() 时出现 TypeError: s 不是函数

问题描述 投票:0回答:1

节目概要: 我正在尝试将图像上传到 Next.js 无服务器后端。我使用 formData() 附加/设置数据并使用 axios 将其 POST 到后端。 在后端,我从 NextRequest 请求 formData(),将其更改为缓冲区并将其保存在服务器文件系统中。

问题: 每当我在前端启动发布时,我都会在 Next.js 控制台上看到错误,提示

TypeError: s is not a function

完整错误:

TypeError: s is not a function
at PATH\node_modules\next\dist\compiled\next-server\app-page.runtime.dev.js:37:5830
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
at async tX (PATH\node_modules\next\dist\compiled\next-server\app-page.runtime.dev.js:37:5207)
at async rl (PATH\node_modules\next\dist\compiled\next-server\app-page.runtime.dev.js:38:22994)
at async doRender (PATH\node_modules\next\dist\server\base-server.js:1407:30)
at async cacheEntry.responseCache.get.routeKind (PATH\node_modules\next\dist\server\base-server.js:1571:28)
at async DevServer.renderToResponseWithComponentsImpl (PATH\node_modules\next\dist\server\base-server.js:1479:28)
at async DevServer.renderErrorToResponseImpl (PATH\node_modules\next\dist\server\base-server.js:2104:24)
at async pipe.req.req (PATH\node_modules\next\dist\server\base-server.js:1982:30)
at async DevServer.pipeImpl (PATH\node_modules\next\dist\server\base-server.js:902:25)

客户端(page.tsx):

"use client";
import React from "react";
import dynamic from "next/dynamic";
import "react-quill/dist/quill.snow.css";
import { useRouter } from "next/navigation";
import axios from "axios";

// Dynamically import ReactQuill to ensure it's only loaded on the client side
const ReactQuill = dynamic(() => import("react-quill"), { ssr: false });

var toolbarOptions = [
    // toolbar options
];

const BLOG_API = "/api/blogs";

export default function WriteBlogPage() {
    const router = useRouter();
    const [title, setTitle] = React.useState("");
    const [image, setImage] = React.useState<File>();
    const [content, setContent] = React.useState("");
    const [slug, setSlug] = React.useState("");

    const handleContentChange = (value: any) => {
        setContent(value);
    };

    const handleFormSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
        e.preventDefault();

        setSlug(title.replaceAll(" ", "-").toLowerCase());
        
        if (!image || !title || !content || !slug) return;


        try {
            const data = new FormData();
            data.append("image", image, image.name);
            data.append("title", title);
            data.append("content", content);
            data.append("slug", slug);
            const response = await axios.post(BLOG_API, data);
            if (response.status === 200) {
                router.push("/");
            } else {
                console.error("Error posting the blog");
            }
        } catch (error) {
            console.error("Error posting the blog:", error);
        }
    };

    return (
        <form onSubmit={handleFormSubmit}>
            <div className="w-full">
                {
                    <ReactQuill
                        value={content}
                        onChange={handleContentChange}
                        modules={{
                            toolbar: toolbarOptions,
                        }}
                        className="text-center"
                        placeholder="Write an epic"
                    />
                }
            </div>
            <input
                type="file"
                accept="image/*"
                onChange={(e) => setImage(e.target.files?.[0])}
            />
        
            <input
                type="text"
                value={title}
                onChange={(e) => setTitle(e.target.value)}
            />
            <button
                type="submit">
                Publish
            </button>
        </form>
    );
}

服务器(route.ts):

// Import necessary modules and models
import { NextRequest, NextResponse } from "next/server";
import { dbConnect as connect } from "@/dbConfig/dbConfig";
import Blog from "@/models/blogModel";
import NodeCache from "node-cache";
import path, { join } from "path";
import { writeFile } from "fs";

// Connect to the database
connect();

// NodeCache configuration for caching
const cache = new NodeCache({
    stdTTL: 1800,
    checkperiod: 300,
});

export const config = {
    api: {
        bodyParser: false,
    },
};

// POST route for creating a new blog
export async function POST(req: NextRequest, res: NextResponse) {
    try {
        const data = await req.formData();
        const image: File | null = data.get("image") as unknown as File;
        const title: String | null = data.get("title") as unknown as String;
        const content: String | null = data.get("content") as unknown as String;
        const slug: String | null = data.get("slug") as unknown as String;

        if (!image || !title || !content || !slug) {
            return NextResponse.json({
                success: false,
                message: "Please pass all necessary data",
            });
        }

        const blogTitle = await Blog.findOne({ title });

        if (blogTitle) {
            return NextResponse.json({
                success: false,
                message:
                    "Already posted. More than one blog of the same title is not allowed",
            });
        }

        const bytes = await image.arrayBuffer();
        const buffer = Buffer.from(bytes);

        const path = join("/","public/uploads/blogs/cover", image.name);

        await writeFile(path, buffer, (error) => {
            return NextResponse.json({
                success: false,
                message: "File save unsuccessful. Please try again.",
            });
        });

        const coverImagePath = join("/uploads/blogs/cover", image.name)

        const blog = new Blog({
            coverImagePath,
            title,
            content,
            slug,
        });

        const savedBlog = await blog.save();

        cache.del("blogs");

        return NextResponse.json({
            message: "Blog posted successfully",
            success: true,
            savedBlog,
        });
    } catch (error: any) {
        return NextResponse.json({ error: error.message }, { status: 500 });
    }
}

我尝试过的:

  • 使用NextApiRequest/NextApiResponse:说我无法像

    Property 'formData' does not exist on type 'NextApiRequest'
    那样访问.formData()。

  • 使用multer并存储图像,但我仍然在控制台上遇到相同的错误。

next.js typeerror multipartform-data multer
1个回答
0
投票

我几个小时前刚刚遇到同样的问题。

事实证明,我没有将 api 文件夹放在应用程序文件夹中,这是保存它的正确位置,并且我认为错误是因为配置或依赖项问题导致了问题(因为我没有它在正确的地方...)

你可以查看Next.js的官方文档,我在阅读此页时就明白了,只需查看Convention部分即可,它说:“Route Handlers 是在app 目录下的route.js|ts 文件中定义的:路由处理程序可以嵌套在app目录中,类似于page.js和layout.js。但是不能有与page.js处于同一路由段级别的route.js文件。”

[https://nextjs.org/docs/app/building-your-application/routing/route-handlers][https://nextjs.org/docs/app/building-your-application/routing/route-handlers ]

希望这对你有帮助....

© www.soinside.com 2019 - 2024. All rights reserved.