logo

存储

简介

在无服务器环境中运行应用程序时,您可能无法将文件永久存储在本地文件系统中,因为您永远无法确定在后续请求中是否会使用相同的无服务器“容器”。所有文件都应存储在云存储系统中,例如 AWS S3,或通过 AWS EFS 存储在共享文件系统中。

附加存储

为了确保应用程序环境有一个地方可以存储文件上传,您可以在环境的 vapor.yml 配置中添加一个 storage 键。此值应为有效的 S3 存储桶名称。在部署期间,Vapor 将确保此存储桶存在。如果存储桶不存在,Vapor 将创建并配置它。请记住,存储桶名称在所有 AWS 中必须是唯一的。

yaml
id: 3
name: vapor-app
environments:
    production:
        storage: my-bucket-name
        memory: 1024
        build:
            - 'composer install --no-dev'
        deploy:
            - 'php artisan migrate --force'

挂载持久文件系统

要在 Lambda 上挂载文件系统,您需要 将您的环境附加到 Vapor 网络,然后使用 AWS 控制台创建一个新的弹性文件系统 (EFS)。在 EFS 仪表板中,您应该单击“创建文件系统”按钮并选择由您的 Vapor 网络创建的 VPC。创建文件系统后,单击其名称以访问配置屏幕,然后单击“访问点”。创建一个访问点,并为“POSIX 用户”和“根目录创建权限”设置的“POSIX 用户”和“组”指定 1001。对于“根目录路径”配置选项,您应该分配一个唯一的名称,例如 /{project_name}_{environment_name}

创建磁盘后,您应该导航到 AWS Lambda 仪表板。进入 Lambda 仪表板后,找到您项目环境的三个 Lambda 函数(主函数、“cli”函数和“queue”函数)中的每一个,并附加您刚刚创建的文件系统。您可以通过查看 Lambda 函数的详细信息页面并单击“添加文件系统”按钮来附加文件系统。您应该将文件系统挂载到 /mnt/local

挂载后,您可以将文件存储到 /mnt/local 磁盘路径并从该路径检索文件。此路径将由所有三个 Lambda 函数共享并可访问。

文件上传

由于 AWS Lambda 的限制,直接上传到应用程序后端的上传文件大小只能达到大约 4.5 MB。这是 AWS 强制执行的硬性限制,更新 php.ini 配置文件或任何其他配置都不会提高此限制。因此,为了确保您的应用程序用户不会收到 HTTP 413 Payload Too Large 响应,您可以在启动文件上传到应用程序后端之前使用 JavaScript 验证文件上传大小。

如果您的应用程序需要接收大于 AWS 允许的文件上传,则这些文件必须从应用程序的前端(浏览器)直接流式传输到 S3。为了帮助您,我们编写了一个 NPM 包,可以轻松地从应用程序的前端执行文件上传。

安装 Vapor NPM 包

要开始使用,请安装 laravel-vapor NPM 包

bash
npm install --save-dev laravel-vapor

接下来,在您的应用程序的app.js文件中,初始化全局 Vapor JavaScript 对象

js
// Vite
import Vapor from 'laravel-vapor'
window.Vapor = Vapor

// Mix
window.Vapor = require('laravel-vapor');

授权

在直接将文件上传到 S3 之前,Vapor 的内部签名存储 URL 生成器将对当前已认证的用户执行授权检查。如果您还没有,您应该使用以下命令为您的应用程序创建一个UserPolicy

bash
php artisan make:policy UserPolicy --model=User

接下来,您应该在此策略中添加一个uploadFiles方法。此方法应在给定的已认证用户被允许上传文件时返回true。否则,您应该返回false

php
/**
 * Determine whether the user can upload files.
 *
 * @param  \App\User  $user
 * @return mixed
 */
public function uploadFiles(User $user)
{
    return true;
}

将文件流式传输到 S3

您可以在前端代码中使用Vapor.store方法将文件直接上传到附加到您的环境的 S3 存储桶。以下示例演示了使用 Vue 的此功能

js
<input type="file" id="file" ref="file">

Vapor.store(this.$refs.file.files[0], {
    progress: progress => {
        this.uploadProgress = Math.round(progress * 100);
    }
}).then(response => {
    axios.post('/api/profile-photo', {
        uuid: response.uuid,
        key: response.key,
        bucket: response.bucket,
        name: this.$refs.file.files[0].name,
        content_type: this.$refs.file.files[0].type,
    })
});

所有上传的文件都将放置在存储桶中的tmp目录中。此目录自动配置为清除任何超过 24 小时的文件。此功能方便地清理了已启动但未完成的文件上传,例如用户开始更新其个人资料照片但未保存更改。

默认情况下,tmp目录是私有的。要为给定文件覆盖此设置,您可以将visibility属性添加到提供给Vapor.store方法的选项中。visibility属性应分配给S3 的预定义权限授予之一

js
Vapor.store(this.$refs.file.files[0], {
    visibility: 'public-read'
}).then(response => {
    // ...
});

确认文件上传和永久存储

所有上传的文件都将使用 UUID 作为文件名进行存储。提供给store方法的then回调的response将包含文件的 UUID、文件的完整 S3 密钥和文件的存储桶。然后,您可以将此信息 POST 到您的应用程序的后端以通过将其移出存储桶的tmp目录来永久存储文件。此外,您可能希望在应用程序的数据库中存储有关文件的其他信息,例如其原始名称和内容类型

php
use Illuminate\Support\Facades\Storage;

Storage::copy(
    $request->input('key'),
    str_replace('tmp/', '', $request->input('key'))
);

本地开发

在本地开发时,Vapor.store将上传到由AWS_BUCKET环境变量指定的存储桶。此外,您的存储桶可能需要 CORS 配置才能允许从 localhost 上传

json
[
   {
      "AllowedHeaders":[
         "*"
      ],
      "AllowedMethods":[
         "GET",
         "PUT"
      ],
      "AllowedOrigins":[
         "*"
      ],
      "ExposeHeaders":[]
   }
]

临时存储

您的应用程序可能会在 /tmp 目录中存储临时文件。默认情况下,此目录的大小固定为 512 MB,并且其中的信息在每个请求、CLI 命令或队列作业的生命周期内都会被保留。您可以使用环境的 vapor.yml 配置文件中的 tmp-storagecli-tmp-storagequeue-tmp-storage 选项来增加或减少配置的临时存储大小。这些配置选项接受 512 MB 到 10,240 MB 之间的数值。

yaml
id: 2
name: vapor-laravel-app
environments:
    production:
        tmp-storage: 1024
        cli-tmp-storage: 512
        queue-tmp-storage: 10240
        build:
            - 'composer install --no-dev'