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
- Bruke multer som et alternativ (merkelige artefakter med NextJS 13 og Typescript) (har prøvd ulike implementasjoner)
- Bruke POST og GET i stedet for PUT i kodeeksemplet
- Googling feilen og også bruke chatgpt
- Å endre versjoner av formidable til v2/v3 og også til v1.2.2 gir samme resultat
- 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
