Skip to content
Edge Functions

文件存储

Use persistent and ephemeral file storage

Edge Functions 提供两种文件存储方式:

🌐 Edge Functions provides two flavors of file storage:

  • 持久 - 支持 S3 协议,可以从任何兼容 S3 的存储桶读写,包括 Supabase Storage
  • 短暂 - 你可以读写 /tmp 目录下的文件。只适合临时操作

你可以使用文件存储来:

🌐 You can use file storage to:

  • 处理复杂的文件转换和工作流程
  • 在项目之间进行数据迁移
  • 处理用户上传的文件并保存它们
  • 解压档案并处理内容后再保存到数据库

持久存储 #

🌐 Persistent Storage

持久存储选项是建立在 S3 协议之上的。它允许你将任何兼容 S3 的存储桶,包括 Supabase 存储桶,挂载为 Edge Functions 的目录。你可以像在 POSIX 文件系统中一样,对挂载的存储桶进行读取和写入文件的操作。

🌐 The persistent storage option is built on top of the S3 protocol. It allows you to mount any S3-compatible bucket, including Supabase Storage Buckets, as a directory for your Edge Functions. You can perform operations such as reading and writing files to the mounted buckets as you would in a POSIX file system.

要从 Edge Functions 访问 S3 存储桶,你必须在 Edge Function Secrets 中为环境变量设置以下内容。

🌐 To access an S3 bucket from Edge Functions, you must set the following for environment variables in Edge Function Secrets.

  • S3FS_ENDPOINT_URL
  • S3FS_REGION
  • S3FS_ACCESS_KEY_ID
  • S3FS_SECRET_ACCESS_KEY

按照此指南 启用并为 Supabase Storage S3 创建访问密钥。

要从你的 Edge Function 访问已挂载桶中的文件路径,请使用前缀 /s3/YOUR-BUCKET-NAME

🌐 To access a file path in your mounted bucket from your Edge Function, use the prefix /s3/YOUR-BUCKET-NAME.

1
// read from S3 bucket
2
const data = await Deno.readFile('/s3/my-bucket/results.csv')
3
4
// make a directory
5
await Deno.mkdir('/s3/my-bucket/sub-dir')
6
7
// write to S3 bucket
8
await Deno.writeTextFile('/s3/my-bucket/demo.txt', 'hello world')

临时存储 #

🌐 Ephemeral storage

临时存储在每次函数调用时都会重置。这意味着你在一次调用中写入的文件只能在同一次调用中读取。

🌐 Ephemeral storage will reset on each function invocation. This means the files you write during an invocation can only be read within the same invocation.

你可以使用 Deno 文件系统 APInode:fs 模块来访问 /tmp 路径。

🌐 You can use Deno File System APIs or the node:fs module to access the /tmp path.

1
Deno.serve(async (req) => {
2
if (req.headers.get('content-type') !== 'application/zip') {
3
return new Response('file must be a zip file', {
4
status: 400,
5
})
6
}
7
8
const uploadId = crypto.randomUUID()
9
await Deno.writeFile('/tmp/' + uploadId, req.body)
10
11
// E.g. extract and process the zip file
12
const zipFile = await Deno.readFile('/tmp/' + uploadId)
13
// You could use a zip library to extract contents
14
const extracted = await extractZip(zipFile)
15
16
// Or process the file directly
17
console.log(`Processing zip file: ${uploadId}, size: ${zipFile.length} bytes`)
18
})

常见用例 #

🌐 Common use cases

使用后台任务处理归档 #

🌐 Archive processing with background tasks

你可以使用临时存储和 后台任务 来处理超过内存限制的大文件处理操作。

🌐 You can use ephemeral storage with Background Tasks to handle large file processing operations that exceed memory limits.

想象一下,你有一个照片相册应用,它接受以 zip 文件形式上传的照片。使用流式实现的话,当 zip 文件超过 100MB 时会遇到内存限制错误,因为它会把所有归档文件同时保存在内存中。

🌐 Imagine you have a Photo Album application that accepts photo uploads as zip files. A streaming implementation will run into memory limit errors with zip files exceeding 100MB, as it retains all archive files in memory simultaneously.

你可以先把 zip 文件写入临时存储,然后用后台任务提取并上传文件到 Supabase 存储。这样,你只需要将 zip 文件的部分内容读入内存。

🌐 You can write the zip file to ephemeral storage first, then use a background task to extract and upload files to Supabase Storage. This way, you only read parts of the zip file to the memory.

1
import { BlobWriter, ZipReader } from 'https://deno.land/x/zipjs/index.js'
2
import { createClient } from 'jsr:@supabase/supabase-js@2'
3
4
const SUPABASE_SECRET_KEYS = JSON.parse(Deno.env.get('SUPABASE_SECRET_KEYS')!)
5
// If you want to use a different api key, change 'default' to your preferred key name
6
const supabase = createClient(Deno.env.get('SUPABASE_URL')!, SUPABASE_SECRET_KEYS['default'])
7
8
async function processZipFile(uploadId: string, filepath: string) {
9
const file = await Deno.open(filepath, { read: true })
10
const zipReader = new ZipReader(file.readable)
11
const entries = await zipReader.getEntries()
12
13
await supabase.storage.createBucket(uploadId, { public: false })
14
15
await Promise.all(
16
entries.map(async (entry) => {
17
if (entry.directory) return
18
19
// Read file entry from temp storage
20
const blobWriter = new BlobWriter()
21
const blob = await entry.getData(blobWriter)
22
23
// Upload to permanent storage
24
await supabase.storage.from(uploadId).upload(entry.filename, blob)
25
26
console.log('uploaded', entry.filename)
27
})
28
)
29
30
await zipReader.close()
31
}
32
33
Deno.serve(async (req) => {
34
const uploadId = crypto.randomUUID()
35
const filepath = `/tmp/${uploadId}.zip`
36
37
// Write zip to ephemeral storage
38
await Deno.writeFile(filepath, req.body)
39
40
// Process in background to avoid memory limits
41
EdgeRuntime.waitUntil(processZipFile(uploadId, filepath))
42
43
return new Response(JSON.stringify({ uploadId }), {
44
headers: { 'Content-Type': 'application/json' },
45
})
46
})

图片处理 #

🌐 Image manipulation

使用 magick-wasm 的自定义图片处理工作流程。

🌐 Custom image manipulation workflows using magick-wasm.

1
Deno.serve(async (req) => {
2
// Save uploaded image to temp storage
3
const imagePath = `/tmp/input-${crypto.randomUUID()}.jpg`
4
await Deno.writeFile(imagePath, req.body)
5
6
// Process image with magick-wasm
7
const processedPath = `/tmp/output-${crypto.randomUUID()}.jpg`
8
// ... image manipulation logic
9
10
// Read processed image and return
11
const processedImage = await Deno.readFile(processedPath)
12
return new Response(processedImage, {
13
headers: { 'Content-Type': 'image/jpeg' },
14
})
15
})

使用同步文件 API #

🌐 Using synchronous file APIs

你可以在初始脚本评估期间安全地使用以下同步 Deno API(以及它们的 Node 对应 API):

🌐 You can safely use the following synchronous Deno APIs (and their Node counterparts) during initial script evaluation:

  • Deno.statSync
  • Deno.removeSync
  • Deno.writeFileSync
  • Deno.writeTextFileSync
  • Deno.readFileSync
  • Deno.readTextFileSync
  • Deno.mkdirSync
  • Deno.makeTempDirSync
  • Deno.readDirSync

记住,同步 API 只在初始脚本评估时可用,并且不支持在回调中使用,例如 HTTP 处理器或 setTimeout

1
Deno.statSync('...') // ✅
2
3
setTimeout(() => {
4
Deno.statSync('...') // 💣 ERROR! Deno.statSync is blocklisted on the current context
5
})
6
7
Deno.serve(() => {
8
Deno.statSync('...') // 💣 ERROR! Deno.statSync is blocklisted on the current context
9
})

限制 #

🌐 Limits

你挂载用于持久存储的 S3 桶没有数量限制。

🌐 There are no limits on S3 buckets you mount for Persistent storage.

临时存储:

🌐 Ephemeral Storage:

  • 免费项目:最多 256MB 临时存储
  • 付费项目:最多512MB的临时存储