node.js - NextJs 13 API for å håndtere opplastede filer fungerer ikke med formidable


Jeg har et NextJs 13-prosjekt som krever et API som kan håndtere en fil som sendes til det. Jeg har brukt formidable for å håndtere mellomvaren

Min app/api/uploadfile/route.ts-fil (koden har blitt minimert for konsentrasjon)

import { IncomingForm } from "formidable";

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

const asyncParse = (req:any) =>
  new Promise((resolve, reject) => {
    const form = new IncomingForm({ multiples: true });
    form.parse(req, (err, fields, files) => {
      if (err) return reject(err);
      resolve({ fields, files });
    });
  });

export async function PUT(req:any, res:any) {
  console.log("Receiving");
  if (req.method === "PUT") {
    const result = await asyncParse(req);
    res.status(200).json({ result });
  }
}

Her kaller jeg API-et ved å bruke endepunktet localhost:3000/api/uploadfile via Postman

Jeg får en feil

error - TypeError: req.on is not a function
    at IncomingForm.parse (webpack-internal:///(sc_server)/./node_modules/formidable/lib/incoming_form.js:90:9)
    at eval (webpack-internal:///(sc_server)/./app/api/uploadfile/route.ts:18:14)
    at new Promise (<anonymous>)
    at asyncParse (webpack-internal:///(sc_server)/./app/api/uploadfile/route.ts:14:27)
    at PUT (webpack-internal:///(sc_server)/./app/api/uploadfile/route.ts:29:30)
    at eval (webpack-internal:///(sc_server)/./node_modules/next/dist/server/future/route-modules/app-route/module.js:219:24)
    at eval (webpack-internal:///(sc_server)/./node_modules/next/dist/server/lib/trace/tracer.js:92:36)
    at NoopContextManager.with (webpack-internal:///(sc_server)/./node_modules/next/dist/compiled/@opentelemetry/api/index.js:360:30)
    at ContextAPI.with (webpack-internal:///(sc_server)/./node_modules/next/dist/compiled/@opentelemetry/api/index.js:30:58)
    at NoopTracer.startActiveSpan (webpack-internal:///(sc_server)/./node_modules/next/dist/compiled/@opentelemetry/api/index.js:953:34)
    at ProxyTracer.startActiveSpan (webpack-internal:///(sc_server)/./node_modules/next/dist/compiled/@opentelemetry/api/index.js:993:36)
    at eval (webpack-internal:///(sc_server)/./node_modules/next/dist/server/lib/trace/tracer.js:81:107)
    at NoopContextManager.with (webpack-internal:///(sc_server)/./node_modules/next/dist/compiled/@opentelemetry/api/index.js:360:30)
    at ContextAPI.with (webpack-internal:///(sc_server)/./node_modules/next/dist/compiled/@opentelemetry/api/index.js:30:58)
    at NextTracerImpl.trace (webpack-internal:///(sc_server)/./node_modules/next/dist/server/lib/trace/tracer.js:81:32)
    at eval (webpack-internal:///(sc_server)/./node_modules/next/dist/server/future/route-modules/app-route/module.js:214:49)
    at AsyncLocalStorage.run (node:async_hooks:345:14)
    at Object.wrap (webpack-internal:///(sc_server)/./node_modules/next/dist/server/async-storage/static-generation-async-storage-wrapper.js:32:24)
    at eval (webpack-internal:///(sc_server)/./node_modules/next/dist/server/future/route-modules/app-route/module.js:171:93)
    at AsyncLocalStorage.run (node:async_hooks:345:14)
    at Object.wrap (webpack-internal:///(sc_server)/./node_modules/next/dist/server/async-storage/request-async-storage-wrapper.js:59:24)
    at AppRouteRouteModule.execute (webpack-internal:///(sc_server)/./node_modules/next/dist/server/future/route-modules/app-route/module.js:170:87)
    at AppRouteRouteModule.handle (webpack-internal:///(sc_server)/./node_modules/next/dist/server/future/route-modules/app-route/module.js:259:41)
    at RouteHandlerManager.handle (E:\Projects\Templates\backend-template\node_modules\next\dist\server\future\route-handler-managers\route-handler-manager.js:22:29)
    at doRender (E:\Projects\Templates\backend-template\node_modules\next\dist\server\base-server.js:848:58)
    at cacheEntry1.responseCache.get.incrementalCache.incrementalCache (E:\Projects\Templates\backend-template\node_modules\next\dist\server\base-server.js:1059:34)
    at E:\Projects\Templates\backend-template\node_modules\next\dist\server\response-cache\index.js:83:42
    at ResponseCache.get (E:\Projects\Templates\backend-template\node_modules\next\dist\server\response-cache\index.js:131:11)
    at DevServer.renderToResponseWithComponentsImpl (E:\Projects\Templates\backend-template\node_modules\next\dist\server\base-server.js:978:54)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)

Ting jeg har prøvd

  1. Bruke multer som et alternativ (merkelige artefakter med NextJS 13 og Typescript) (har prøvd ulike implementasjoner)
  2. Bruke POST og GET i stedet for PUT i kodeeksemplet
  3. Googling feilen og også bruke chatgpt
  4. Å endre versjoner av formidable til v2/v3 og også til v1.2.2 gir samme resultat
  5. Bedre kode for å laste opp til min Prisma database (men det feiler i selve API-kallsteget)

Mitt endelige mål

Jeg vil bruke dette API-endepunktet i min ckeditor5-implementering (som bildeforsendelsesadapter)

Svar #1

Du trenger ikke formidable lenger for det. Next.js 13 la til en ny funksjon formData(); i applikasjonen deres som håndterer filopplasting, og de begrenset bruken av formidable som håndterer denne funksjonaliteten. Så dette er det (jeg svarer på målet ditt: å bruke CKEditor5 for å håndtere dette. Kan også fungere ved bruk av Postman):

  const formData = await request.formData();
  const file: any = formData.get("upload");

For meg trengte jeg filen til å bli lastet opp på Cloudinary, så dette er hvordan jeg løste det.

 const formData = await request.formData();
    const file: any = formData.get("upload");
    
    const arrayBuffer = await file.arrayBuffer();
    const buffer = new Uint8Array(arrayBuffer);

    let uploadedImageUrl: any = await new Promise((resolve, reject) => {
      cloudinary.uploader
        .upload_stream({}, function (error, result: any) {
          if (error) {
            reject(error);
            return;
          }

          resolve(result);
        })
        .end(buffer);
    });

Hvis du console.log(result), vil du se den returnerte verdien av filen din. Returner secure_url, og det vil returnere bildet til editoren.

Svar #2

Det virker som om vi ikke trenger formidable, multer eller multiparty med Nextjs siden det håndterer dette. Hvis du støter på et lignende problem, prøv dette. https://github.com/vercel/next.js/issues/48875#issuecomment-1592301037

Relaterte artikler