@Tars_Tarkas
Junior React Developer

Как в Next JS, отправка файлов на сервер с указанием пути сохранения?

Новичек в написании серверного приложения.
Подскажите как при копировании и сохранения файлов на сервере, сохранять в указанную поддиректорию

Код компонента для отправки
mport { useState, useRef } from "react";

export default function Admin() {
  const [isLoading, setIsLoading] = useState(false);
  const inputFileRef = useRef<HTMLInputElement | null>(null);
  const inputTextRef = useRef<HTMLInputElement | null>(null);

  const folder= "foto";

  const handleOnClick = async (e: React.MouseEvent<HTMLInputElement>) => {
    e.preventDefault();

    if (!inputFileRef.current?.files?.length) {
      alert("Выберите изображения для загрузки");
      return;
    }
 
    setIsLoading(true);

    const formData = new FormData();
    Object.values(inputFileRef.current.files).forEach((file) => {
      formData.append("file", file);
    });
    formData.append("folder", folder);

    const response = await fetch("/api/upload", {
      method: "POST",
      body: formData,
    });

    const body = (await response.json()) as {
      status: "ok" | "fail";
      message: string;
    };
   setIsLoading(false);
  };

  return (
    <form>
      <div>
        <input type="text" name="text" ref={inputTextRef} defaultValue="foto" />
        <input type="file" name="myfile" ref={inputFileRef} multiple />
      </div>
      <div>
        <input
          type="submit"
          value="Upload"
          disabled={isLoading}
          onClick={handleOnClick}
        />
        {isLoading && ` Подождите...`}
      </div>
    </form>
  );
}


Код Api на сервере

import { NextApiHandler, NextApiRequest } from "next";
import formidable from "formidable";
import path from "path";
import fs from "fs/promises";

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

const readFile = (
  req: NextApiRequest,
  saveLocally?: boolean
): Promise<{
  fields: formidable.Fields;
  files: formidable.Files;
}> => {
  const options: formidable.Options = {};
  if (saveLocally) {
    options.uploadDir = path.join(process.cwd(), "/public/img");
    options.filename = (name, ext, path, form): any => {
      return path.originalFilename;
    };
  }
  // options.maxFileSize = 4000 * 1024 * 1024;
  const form = formidable(options);
  return new Promise((resolve, reject) => {
    form.parse(req, (err, fields, files) => {
      // let text = fields.text?.join(" ")!;
      if (err) reject(err);
      resolve({ fields: {}, files: {} });
    });
  });
};

const handler: NextApiHandler = async (req, res) => {
  try {
    await fs.readdir(path.join(process.cwd() + "/public", "/img"));
  } catch (error) {
    await fs.mkdir(path.join(process.cwd() + "/public", "/img"));
  }
  await readFile(req, true);
  res.json({ done: "ok" });
};

export default handler;
  • Вопрос задан
  • 380 просмотров
Пригласить эксперта
Ответы на вопрос 1
@Tars_Tarkas Автор вопроса
Junior React Developer
может кому нибудь пригодится мое решение:

файл api/upload/route.ts

import mime from "mime";
import { join } from "path";
import { stat, mkdir, writeFile } from "fs/promises";
import { NextRequest, NextResponse } from "next/server";

export async function POST(request: NextRequest) {
  const formData = await request.formData();
  const file = formData.get("file") as Blob | null;

  if (!file) {
    return NextResponse.json(
      { error: "File blob is required." },
      { status: 400 }
    );
  }
  const folder = formData.get("folder") as string;

  const relativeUploadDir = `/portfolio/${folder}`;
  const uploadDir = join(process.cwd(), "public/", relativeUploadDir);

  try {
    await stat(uploadDir);
  } catch (e: any) {
    if (e.code === "ENOENT") {
      await mkdir(uploadDir, { recursive: true });
    } else {
      console.error(
        "Ошибка при попытке создать каталог при загрузке файла\n",
        e
      );
      return NextResponse.json(
        { error: "Что-то пошло не так." },
        { status: 500 }
      );
    }
  }

  try {
    const folderArray = [];
    const formDataEntryValues = Array.from(formData.values()) as [];
    for (const formDataEntryValue of formDataEntryValues) {
      if (
        typeof formDataEntryValue === "object" &&
        "arrayBuffer" in formDataEntryValue
      ) {
        const file = formDataEntryValue as unknown as Blob;
        const buffer = Buffer.from(await file.arrayBuffer());
        await writeFile(`${uploadDir}/${file.name}`, buffer);
        folderArray.push(`${relativeUploadDir}/${file.name}`);
      }
    }
    return NextResponse.json({ filename: folderArray });
  } catch (e) {
    console.error("Error while trying to upload a file\n", e);
    return NextResponse.json({ error: "Что-то пошло не так" }, { status: 500 });
  }
}
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы