如何获取我以输入文件形式选择的文件的路径,以便我可以在服务器端使用 cloudinary 上传

How to get the path of the file I selected in a form of input file so I can upload with cloudinary the server side

我能够获取图片对象下文件的文件名,如下图所示

我向 cloudinary 发出以下请求,但它说图像路径不正确,这是有道理的,但我为所选图片拥有的对象不显示图像路径。

那么如何获得 cloudinary 的正确路径。

var cloudinary = require("cloudinary").v2;

cloudinary.config({
  cloud_name: process.env.CLOUDINARY_NAME,
  api_key: process.env.CLOUDINARY_API_KEY,
  api_secret: process.env.CLOUDINARY_API_SECRET,
});

export default async function signup(req, res) {
  console.log(req.body);
  const body = req.body;

  cloudinary.uploader.upload(
    `${body}`,
    function (error, result) {
      console.log(result, error);
    }
  );

  try {
    const result = req.body;
    res.status(200).send(result);
  } catch (error) {
    console.error(error);
    res.status(error.requestResult.statusCode).send(error.message);
  }
}

这是我要发送给 api

的内容
 const res = await fetch("../api/image", {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify(data.picture[0].name),
    });

    console.log(res);

我正在使用 React 钩子形式,这里是上下文的完整代码

import { useForm, Controller } from "react-hook-form";
import Layout from "../components/Layout";
import ReactDatePicker from "react-datepicker";
import "react-datepicker/dist/react-datepicker.css";
import { gql, useMutation } from "@apollo/client";
import useSWR from "swr";
import { useRouter } from "next/router";

const CREATE_DECOR_ENTRY = gql`
  mutation CreateDecorEntry(
    $ownerID: ID!
    $description: String!
    $pieces: Int!
    $purchaser: String!
    $alterations: Boolean!
    $cost: Int!
    $purchaseDate: Date!
    $category: String!
  ) {
    createDecor(
      data: {
        description: $description
        pieces: $pieces
        purchaser: $purchaser
        alterations: $alterations
        cost: $cost
        purchaseDate: $purchaseDate
        category: $category
        owner: { connect: $ownerID }
      }
    ) {
      description
    }
  }
`;

const fetcher = (url) => fetch(url).then((r) => r.json());
const fetchWithImage = (url, image) =>
  fetch(`${url}?image=${image}`).then((r) => r.json());

export default function Decor() {
  const { data: user, error: userError } = useSWR("/api/user", fetcher);

  const { data: cookieData, error: cookieError } = useSWR(
    "/api/cookie",
    fetcher
  );

  var cookieBearer = `Bearer ${cookieData}`;

  return (
    <Layout>
      <h1>Enter your Decor Data</h1>

      {user && cookieBearer && <Form user={user} cookieBearer={cookieBearer} />}
    </Layout>
  );
}

const Form = ({ cookieBearer, user }) => {
  const Router = useRouter();

  const [
    createDecorEntry,
    { data: createDecorEntryData, loading: saving },
  ] = useMutation(CREATE_DECOR_ENTRY, {
    context: {
      headers: {
        authorization: cookieBearer,
      },
    },
  });

  const { register, handleSubmit, errors, control } = useForm();
  const onSubmit = async (data) => {
    console.log(data);

    let yourDate = data.purchaseDate;

    const offset = yourDate.getTimezoneOffset();
    yourDate = new Date(yourDate.getTime() - offset * 60 * 1000);
    const date = yourDate.toISOString().split("T")[0];

    console.log(date);

    const dataMassage = {
      ...data,
      pieces: parseInt(data.pieces),
      cost: parseInt(data.cost),
      purchaseDate: date,
    };

    console.log(dataMassage);

    const res = await fetch("../api/image", {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify(data.picture[0].name),
    });

    console.log(res);

    // const res = await createDecorEntry({
    //   variables: {
    //     ownerID: user.id,
    //     ...dataMassage,
    //   },
    // }).catch(console.error);

    // Router.push(`/decor/data`);
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <div>
        <h2>Image</h2>
        <input ref={register} type="file" name="picture" />
      </div>
      <div>
        <h2>Description</h2>
        <input
          type="text"
          placeholder="Description"
          name="description"
          ref={register({ required: true })}
        />
      </div>
      <div>
        <h2>Number of Pieces</h2>
        <input
          type="number"
          placeholder="Number of Pieces"
          name="pieces"
          ref={register({ required: true })}
        />
      </div>
      <div>
        <h2>Purchaser</h2>
        <input
          type="text"
          placeholder="Purchaser"
          name="purchaser"
          ref={register({ required: true })}
        />
      </div>
      <div>
        <h2>Alternations Needed</h2>
        <input
          type="checkbox"
          placeholder="Alternations Needed"
          name="alterations"
          ref={register({ required: true })}
        />
      </div>
      <div>
        <h2>Cost</h2>
        <input
          type="number"
          placeholder="Cost"
          name="cost"
          ref={register({ required: true })}
        />
      </div>
      <div>
        <h2>Purchase Date</h2>
        <Controller
          name="purchaseDate"
          control={control}
          render={({ onChange, value }) => (
            <ReactDatePicker selected={value} onChange={onChange} />
          )}
        />
      </div>
      <div>
        <h2>Category</h2>
        <select name="category" ref={register}>
          <option value="Curation">Curation</option>
          <option value=" Good"> Good</option>
        </select>
      </div>

      <div>
        <input type="submit" />
      </div>
    </form>
  );
};

根据documentation, you can't just upload file. You will have to either save it somewhere first (for example locally on disk), or

有趣的是,文档的其他部分建议您发送 array buffer,但我不确定它是否在 Node

中可用

我发布这个答案只是为了让其他人受益,我最终选择了数组缓冲区路线。

import formidable from "formidable";
const cloudinary = require("cloudinary").v2;
const fs = require("fs");
const path = require("path");
let streamifier = require('streamifier');

cloudinary.config({
  cloud_name: process.env.CLOUDINARY_NAME,
  api_key: process.env.CLOUDINARY_API_KEY,
  api_secret: process.env.CLOUDINARY_API_SECRET,
});

// first we need to disable the default body parser
export const config = {
  api: {
    bodyParser: false,
  },
};

export default async function image(req, res) {
  

  try {

    const form = new formidable.IncomingForm();
  form.uploadDir = "./";
  form.keepExtensions = true;
  form.parse(req, (err, fields, files) => {
    console.log(JSON.stringify(files));

    console.log(files.image.path);

    var oldPath = files.image.path;
    var rawData = fs.readFileSync(oldPath);

    console.log(rawData);

    let cld_upload_stream = cloudinary.uploader.upload_stream(
      {
        folder: "sick-fits"
      },
      function(error, result) {
          console.log(error, result);
          res.status(200).send({ result });
      }
  );

  streamifier.createReadStream(rawData).pipe(cld_upload_stream);

  });

  } catch (error) {
    console.error(error);
    res.status(error.requestResult.statusCode).send(error.message);
  }
}