Laravel 不原生支持七牛云,因其签名机制、API 协议、鉴权头等与 AWS S3 完全不兼容;必须使用专为七牛设计的 Flysystem 适配器(如 zgldh/qiniu-laravel-storage),正确配置 domains(非 domain)并避免路径开头斜杠。

直接说结论:Laravel 本身不原生支持七牛云,所谓「扩展 S3 驱动上传到七牛」是常见误解——七牛云 不是 S3 兼容对象存储,不能靠改 endpoint 或 region 模拟 S3 驱动工作。强行用 Aws\S3\S3Client + 七牛域名会返回 SignatureDoesNotMatch 或 InvalidAccessKeyId 错误。
为什么不能直接复用 Laravel 的 s3 驱动
七牛云的签名机制(QiniuMac)、上传协议(putFile + token)、元数据字段(x-qn-meta-*)和鉴权头(Authorization: QBox ...)与 AWS S3 完全不兼容。Laravel 的 s3 驱动底层调用的是 Aws\S3\S3Client,它只认 AWS 签名 v4 和 S3 REST API 格式。
常见错误现象:
Client error: POST https://up-z2.qiniup.com resulted in a 401 Unauthorized response: {"error":"invalid authorization"}-
InvalidArgumentException: Missing required client configuration options: region(硬塞 region 也无效) - 上传成功但文件内容为空或损坏(因 body 被 S3 驱动自动加了 multipart/form-data 封装)
正确做法:用专为七牛设计的 Flysystem 适配器
必须使用基于 league/flysystem 实现的七牛适配器,它接管了整个上传流程:生成 token、构造 HTTP 请求、处理响应。主流选择有三个包,区别关键在维护状态和 Laravel 版本兼容性:
-
zgldh/qiniu-laravel-storage:最常用,Laravel 5.5–10.x 全支持,domains配置支持 http/https/custom 多域名切换 -
overtrue/laravel-filesystem-qiniu:轻量,但已多年未更新(最后 commit 2020),不推荐新项目 -
itbdw/laravel-storage-qiniu:极简封装,无 CDN 域名管理,适合只用默认域名的场景
推荐执行:
composer require zgldh/qiniu-laravel-storage
然后在 config/app.php 的 providers 数组中添加:
zgldh\QiniuStorage\QiniuFilesystemServiceProvider::class
配置 disks 时 domain 和 domains 的区别
这是最容易配错的地方:zgldh/qiniu-laravel-storage 要求用 domains(复数),不是 domain(单数)。写成 'domain' => 'xxx.clouddn.com' 会导致 downloadUrl() 返回空字符串或报错。
Laravel Cloud(cloud.laravel.com)。此技能用于处理所有 Laravel Cloud 请求,包括搜索和读取数据。只要任务涉及 Laravel Cloud,即使用此技能。
正确配置节选(config/filesystems.php):
'qiniu' => [
'driver' => 'qiniu',
'domains' => [
'default' => 'xxx.clouddn.com',
'https' => 'https://xxx.clouddn.com',
],
'access_key' => env('QINIU_ACCESS_KEY'),
'secret_key' => env('QINIU_SECRET_KEY'),
'bucket' => env('QINIU_BUCKET'),
],
注意:
- 如果只配
default,Storage::disk('qiniu')->url('foo.jpg')返回的是http://xxx.clouddn.com/foo.jpg - 若需强制 HTTPS,得手动调用
Storage::disk('qiniu')->getDriver()->downloadUrl('foo.jpg', 'https') -
notify_url是可选项,仅用于触发七牛持久化处理(如缩略图、水印),不填不影响基础上传
上传时 putFileAs 和 put 的路径处理差异
七牛的 key(即文件在 bucket 中的路径)不能以 / 开头,否则上传后 URL 会多出一层空目录或 404。而 Laravel 的 putFileAs() 默认会在你传入的目录前加 /,比如:
$disk->putFileAs('images', $request->file('avatar'), '123.png');
实际生成的 key 是 /images/123.png —— 这在七牛上会被解释为根目录下名为 images 的文件,而非 images/ 目录下的文件。
安全写法是显式拼接路径并去掉开头斜杠:
$path = 'images/' . md5_file($file->getRealPath()) . '.' . $file->getClientOriginalExtension(); $disk->put(ltrim($path, '/'), file_get_contents($file->getRealPath()));
或者更稳妥地用 putFile()(它内部会自动 normalize 路径):
$disk->putFile('images', $request->file('avatar'));
真正容易被忽略的点是:七牛 token 有效期默认 3600 秒,但如果你在高并发上传场景下复用同一个 token,或在 token 过期后仍尝试上传,putFile 会静默失败(返回 false)且不抛异常。务必在每次上传前确保 token 新鲜,而 zgldh/qiniu-laravel-storage 内部已自动处理 token 刷新逻辑——所以别自己手动生成和缓存 token。


















