Laravel的文件系统(Filesystem)如何对接S3或OSS? (多云存储配置)

11次阅读

laravel中需分别配置S3和OSS磁盘,OSS必须用阿里官方SDK封装的Flysystem适配器注册自定义驱动,不可复用s3配置;通过Storage::disk(‘oss’)显式调用,注意URL生成、权限策略及环境变量隔离。

Laravel的文件系统(Filesystem)如何对接S3或OSS? (多云存储配置)

如何在 Laravel 中配置多个云存储驱动(S3/OSS)

Laravel 的 Filesystem 支持多磁盘配置,但默认只预设了 s3 驱动;对接阿里云 OSS 需要手动注册自定义驱动,不能直接复用 s3 配置。核心在于:OSS 兼容 S3 协议,但认证方式、Endpoint 规则、签名逻辑有差异,必须用适配过的 SDK 驱动。

  • 不要把 OSS 的 endpoint 直接填进 filesystems.phps3 配置里——Laravel 原生 s3 驱动会错误拼接 URL,导致 403 或 404
  • 推荐使用 league/flysystem-aws-s3-v3 + aliyuncs/oss-sdk-php 分开管理:S3 用官方驱动,OSS 必须用阿里官方 SDK 封装的 Flysystem 适配器
  • 多云场景下,每个磁盘需独立声明驱动类型,不能共用 default 磁盘别名

注册 OSS 驱动并配置磁盘

appProvidersAppServiceProvider::boot() 中注册 oss 驱动,依赖 aliyuncs/oss-sdk-phpovertrue/flysystem-oss(轻量封装,比手写 Adapter 更稳)。

use IlluminateSupportFacadesStorage; use LeagueFlysystemFilesystem; use OvertrueFlysystemOssAdapter; use AlibabaCloudOSSOssClient;  public function boot() {     Storage::extend('oss', function ($app, $config) {         $client = new OssClient(             $config['access_key_id'],             $config['access_key_secret'],             $config['endpoint'],             false // 不自动开启 CNAME         );          return new Filesystem(new OssAdapter($client, $config['bucket'], $config['prefix'] ?? ''));     }); }

然后在 config/filesystems.php 新增磁盘:

'disks' => [     's3' => [         'driver' => 's3',         'key' => env('AWS_ACCESS_KEY_ID'),         'secret' => env('AWS_SECRET_ACCESS_KEY'),         'region' => env('AWS_DEFAULT_REGION'),         'bucket' => env('AWS_BUCKET'),         'url' => env('AWS_URL'),         'endpoint' => env('AWS_ENDPOINT'), // S3 兼容服务(如 MinIO)才需要     ],      'oss' => [         'driver' => 'oss',         'access_key_id' => env('OSS_ACCESS_KEY_ID'),         'access_key_secret' => env('OSS_ACCESS_KEY_SECRET'),         'endpoint' => env('OSS_ENDPOINT'), // 如 'https://oss-cn-hangzhou.aliyuncs.com'         'bucket' => env('OSS_BUCKET'),         'prefix' => env('OSS_PREFIX', ''),     ], ]

使用时如何避免跨磁盘误操作

调用 Storage::disk('xxx') 是显式且安全的,但容易踩的坑是:全局辅助函数 storage_path() 只指向本地 storage/app,和磁盘无关;Storage::put() 默认走 default 磁盘,不指定就是 local

  • 上传到 OSS 必须写全: Storage::disk('oss')->put('images/photo.jpg', $content)
  • 生成可访问 URL:S3 磁盘用 Storage::disk('s3')->url('path');OSS 磁盘需额外配置 url 键或重写 OssAdapter::getUrl(),否则返回空字符串
  • 删除操作不支持跨磁盘通配符,Storage::deleteDirectory() 在 OSS 上实际是逐个 delete,注意大目录可能超时

环境变量与敏感信息隔离

多云配置意味着更多密钥字段,.env 里必须严格区分前缀,避免混淆:

AWS_ACCESS_KEY_ID=AKIA... AWS_SECRET_ACCESS_KEY=... AWS_BUCKET=my-bucket AWS_DEFAULT_REGION=us-east-1  OSS_ACCESS_KEY_ID=LTai... OSS_ACCESS_KEY_SECRET=... OSS_BUCKET=my-oss-bucket OSS_ENDPOINT=https://oss-cn-hangzhou.aliyuncs.com

OSS 的 access_key_id 格式以 LTAI 开头,S3 是 AKIA,这个特征可用于部署时做简单校验,防止环境错绑。

真正麻烦的是权限策略粒度:S3 的 IAM Policy 和 OSS 的 RAM Policy 写法完全不同,即使配置对了,也会因最小权限原则导致 403;建议先用主账号密钥验证流程,再逐步收紧权限。

text=ZqhQzanResources