跳转到内容

File Uploads

本文档尚未完成:它是从文件上传 API 文档中提取的,因此有点脱离上下文。我们打算将其重写为文件上传的一般指南。

大多数时候,您可能希望将文件代理到文件主机。

例子:

import type {
ActionFunctionArgs,
UploadHandler,
} from "@remix-run/node"; // or cloudflare/deno
import {
unstable_composeUploadHandlers,
unstable_createMemoryUploadHandler,
unstable_parseMultipartFormData,
} from "@remix-run/node"; // or cloudflare/deno
import { writeAsyncIterableToWritable } from "@remix-run/node"; // `writeAsyncIterableToWritable` is a Node-only utility
import type {
UploadApiOptions,
UploadApiResponse,
UploadStream,
} from "cloudinary";
import cloudinary from "cloudinary";
async function uploadImageToCloudinary(
data: AsyncIterable<Uint8Array>
) {
const uploadPromise = new Promise<UploadApiResponse>(
async (resolve, reject) => {
const uploadStream =
cloudinary.v2.uploader.upload_stream(
{
folder: "remix",
},
(error, result) => {
if (error) {
reject(error);
return;
}
resolve(result);
}
);
await writeAsyncIterableToWritable(
data,
uploadStream
);
}
);
return uploadPromise;
}
export const action = async ({
request,
}: ActionFunctionArgs) => {
const userId = getUserId(request);
const uploadHandler = unstable_composeUploadHandlers(
// our custom upload handler
async ({ name, contentType, data, filename }) => {
if (name !== "img") {
return undefined;
}
const uploadedImage = await uploadImageToCloudinary(
data
);
return uploadedImage.secure_url;
},
// fallback to memory for everything else
unstable_createMemoryUploadHandler()
);
const formData = await unstable_parseMultipartFormData(
request,
uploadHandler
);
const imageUrl = formData.get("avatar");
// because our uploadHandler returns a string, that's what the imageUrl will be.
// ... etc
};

UploadHandler 函数接受有关文件的多个参数:

PropertyTypeDescription
namestringThe field name (comes from your HTML form field “name” value)
dataAsyncIterableThe iterable of the file bytes
filenamestringThe name of the file that the user selected for upload (like rickroll.mp4)
contentTypestringThe content type of the file (like videomp4)

您的工作是使用数据执行任何您需要的操作,并返回一个有效的 [FormData][form-data] 值:[File][the-browser-file-api]、stringundefined,以跳过将其添加到生成的 FormData 中。

上传处理程序组成

我们有内置的 unstable_createFileUploadHandlerunstable_createMemoryUploadHandler,并且我们还希望将来开发更多的上传处理程序实用程序。如果您的表单需要使用不同的上传处理程序,您可以使用自定义处理程序将它们组合在一起,这是一个理论示例:

file-upload-handler.server.ts
import type { UploadHandler } from "@remix-run/node"; // or cloudflare/deno
import { unstable_createFileUploadHandler } from "@remix-run/node"; // or cloudflare/deno
import { createCloudinaryUploadHandler } from "some-handy-remix-util";
export const standardFileUploadHandler =
unstable_createFileUploadHandler({
directory: "public/calendar-events",
});
export const cloudinaryUploadHandler =
createCloudinaryUploadHandler({
folder: "/my-site/avatars",
});
export const fileUploadHandler: UploadHandler = (args) => {
if (args.name === "calendarEvent") {
return standardFileUploadHandler(args);
} else if (args.name === "eventBanner") {
return cloudinaryUploadHandler(args);
}
return undefined;
};