要在Laravel中真正掌控文件存储行为,必须绕过Storage门面直接与Flysystem交互,并通过多磁盘配置实现运行时动态切换:在config/filesystems.php中定义avatars(local)和videos(s3)磁盘,控制器中根据MIME类型选择磁盘,用getDriver()获取FlysystemAdapter后调用writeStream()写入流资源。

要在Laravel中真正掌控文件存储行为,必须绕过表层的Storage门面,直接与Flysystem抽象层交互,并通过多磁盘配置实现运行时动态切换——这决定了你的应用能否在不改一行业务代码的前提下,把用户头像存本地、视频推S3、PDF归档到MinIO。
理解Flysystem在Laravel中的真实角色
Flysystem不是Laravel自带的组件,而是通过league/flysystem包注入的第三方抽象层,Laravel只是做了封装和驱动适配。你调用Storage::disk('s3')->put()时,实际执行的是Flysystem\FilesystemAdapter->write(),中间经过了Laravel的FilesystemManager路由分发。
关键点在于:Flysystem本身不处理环境差异,它只提供read、write、listContents等统一方法;Laravel的config/filesystems.php才是决定“哪个物理位置被调用”的开关。
如果你跳过配置直接new一个Flysystem实例,它就脱离了Laravel生命周期管理,无法自动读取.env里的密钥,也不会触发事件监听器。
配置多个磁盘并启用运行时切换
打开config/filesystems.php,在'disks'数组里追加至少两个不同驱动的磁盘定义:
本地公开磁盘用于头像:'avatars' => ['driver' => 'local', 'root' => public_path('uploads/avatars'), 'visibility' => 'public']
AWS S3磁盘用于视频:'videos' => ['driver' => 's3', 'key' => env('AWS_ACCESS_KEY_ID'), 'secret' => env('AWS_SECRET_ACCESS_KEY'), 'region' => 'us-east-1', 'bucket' => env('AWS_VIDEO_BUCKET')]
【必须确保.env中已定义AWS_VIDEO_BUCKET且值非空】否则S3磁盘初始化失败,后续调用会抛出InvalidArgumentException而非静默降级。
保存后运行php artisan config:clear,避免配置缓存干扰。
在控制器中动态选择磁盘并写入文件
第一步:接收上传的文件对象
使用$request->file('media')获取Illuminate\Http\UploadedFile实例,不要提前调用store()——那是封装过的快捷方法,会锁定默认磁盘。
第二步:根据MIME类型判断目标磁盘
调用$file->getMimeType(),若返回image/jpeg或image/png,则选avatars磁盘;若为video/mp4或video/quicktime,则选videos磁盘。
第三步:手动实例化对应磁盘的Flysystem适配器
用Storage::disk($diskName)->getDriver()获取底层Flysystem\FilesystemAdapter对象,这是直通Flysystem API的入口。
第四步:执行原始写入操作
调用$adapter->writeStream($path, $file->getStream()),传入原生PHP流资源,绕过Laravel的临时文件移动逻辑,避免大文件二次加载内存。


















