优先选用 jacobcyl/ali-oss-storage 包,它深度集成 flysystem,支持自动分片上传(>100mb)、temporaryurl 等全部 laravel storage 方法,配置时 endpoint 必须为纯域名(如 oss-cn-hangzhou.aliyuncs.com),不可带协议或 bucket 名。

直接用 Laravel 自带的 Storage 就能接,不用写一堆 SDK 初始化代码,前提是选对包、配对配置、别把 endpoint 写错。
选哪个 Composer 包最省事
优先用 jacobcyl/ali-oss-storage(Laravel 9–11 兼容),不是官方 SDK(aliyuncs/oss-sdk-php)——后者要自己封装客户端、处理异常、管理连接,而前者已深度集成 Flysystem,Storage::disk('oss') 开箱即用。
- 别用
johnlui/aliyun-oss:已多年未维护,PHP 8.2+ 报Deprecated: strlen(): Passing null to parameter - 别手写
OssClient实例:容易漏掉重试、超时、分片上传逻辑,大文件(>100MB)会卡死或超时 -
jacobcyl/ali-oss-storage支持分片上传自动触发(>100MB 默认启用),且兼容 Laravel 的putFile、stream、temporaryUrl等全部方法
config/filesystems.php 里 disk 配置的关键点
endpoint 必须是纯域名,不能带 http:// 或 https://,也不能拼上 bucket 名;否则 Storage::put() 会抛出 cURL error 6: Could not resolve host 或 403 Forbidden。
- 正确写法:
'endpoint' => 'oss-cn-hangzhou.aliyuncs.com' - 错误写法:
'endpoint' => 'https://my-bucket.oss-cn-hangzhou.aliyuncs.com'(多加了协议和 bucket) - 内网 endpoint(如 ECS 同地域部署)用
oss-cn-hangzhou-internal.aliyuncs.com,但必须确认 ECS 和 OSS 在同一可用区,否则连不通 -
'isCName' => true时,Storage::url()返回的是你配置的cdnDomain,不是 OSS 原始域名;设为false则返回https://bucket-name.endpoint/...
上传失败常见报错和对应解法
大多数上传失败不是代码问题,而是环境或配置细节没对齐。
-
InvalidAccessKeyId:检查.env中OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET是否复制完整,有无空格或换行;AccessKey 必须是「主账号」或「RAM 子用户」的,不能是临时 STS Token -
BucketNotExists:确认OSS_BUCKET值与阿里云控制台里 Bucket 名字**完全一致**(区分大小写),且该 Bucket 所在 region 与 endpoint 一致(例如oss-cn-shenzhen对应oss-cn-shenzhen.aliyuncs.com) -
cURL error 28: Operation timed out:小文件('timeout' => 300 和'connect_timeout' => 30 - 前端上传后返回 400 / 500 但日志没报错:检查
APP_DEBUG=false时是否关闭了debug模式('debug' => false会导致 SDK 不输出具体错误)
大文件(>500MB)上传必须注意的事
Laravel 默认用 $request->file()->store() 是读进内存再传,会爆内存。必须绕过框架默认流程,走流式或分片。
- 不要用
Storage::put('video.mp4', file_get_contents($path)):1GB 文件会吃光 PHP 内存 - 改用
Storage::putFile('videos/', $request->file('video')):底层自动判断大小,>100MB 触发 multipart upload - 若需自定义分片逻辑(比如断点续传),得用
aliyuncs/oss-sdk-php的OssClient::initiateMultipartUpload,但代价是脱离 Laravel Storage 统一接口,后续删除、URL 生成都得手动写 - 上传前务必验证:
$request->validate(['video' => 'required|file|mimetypes:video/mp4,video/x-ms-wmv|max:1024000'])(单位 KB)
真正卡住人的从来不是“怎么连上”,而是 endpoint 多写了 https、bucket 名少了个字母、AccessKey 权限没开足、或者以为配完就能直接 put 大文件——其实得看包有没有帮你兜住分片逻辑。











