uploadFile是Webman中稳定上传大文件的唯一可行方式,因putObject在Swoole协程下会阻塞Worker进程,导致Nginx超时返回504;其不支持分片、断点续传与重试,易触发cURL timeout或OOM,生产环境必须弃用。

uploadFile 是 Webman 中稳定上传大文件的唯一可行方式,putObject 在协程环境下必然阻塞 Worker,上传视频类文件时大概率触发 504 或 cURL timeout。
为什么 putObject 在 Webman 里根本不能用
Webman 基于 Swoole 运行,而官方 PHP SDK 的 putObject 底层调用同步 cURL,会锁死当前协程 —— 不是“慢”,而是整个 Worker 进程卡住,无法处理其他请求。上传一个 20MB 视频时,若网络稍有延迟,Nginx/ALB 的 60 秒超时立刻生效,返回 504 Gateway Timeout;日志里常伴随 cURL error 28: Operation timed out 或 Connection reset by peer。
它还不支持断点续传、不自动分片、不重试,纯靠单次 HTTP 请求扛到底。在生产环境等同于裸奔。
-
putObject只适合 CLI 脚本或传统 FPM 场景,Webman 中请彻底弃用 - 哪怕上传小图,也建议统一走
uploadFile,避免后期扩容时踩坑 - 若硬要用
putObject,必须配合fopen($file, 'rb')流式读取,否则大文件直接 OOM
uploadFile 必须配的三个参数
uploadFile 是 SDK 内部封装了 initMultipartUpload + 分片上传 + 自动重试的接口,但默认配置极不友好:分片太小会发几百个请求拖慢速度,重试次数太少又扛不住弱网。
立即学习“PHP免费学习笔记(深入)”;
-
'partSize' => 5 * 1024 * 1024:设为 5MB,兼顾并发数与单请求稳定性(太小如 1MB,100MB 文件要发 100+ 请求) -
'maxRetries' => 3:默认是 0,必须显式设为 ≥2,否则一次网络抖动就失败 -
'contentType' => mime_content_type($tmp_file):不传会触发 OSS 自动探测,对 MP4 等格式常误判为application/octet-stream,导致浏览器无法内联播放
临时路径也要留意:uploadFile 会把分片写入本地磁盘(如 /tmp),PHP 进程必须对该目录有读写权限,否则报 failed to open stream: Permission denied。
环境变量驱动的客户端初始化才安全
每次请求都 new OssClient 会反复解析 endpoint、重建连接池,浪费资源;在 config/autoload/oss.php 里硬编码密钥更危险,容易误提交到 Git。
正确做法是在 app/bootstrap.php 中绑定容器单例:
$container->bind('OssClient', function ($container) {
return new \Aliyun\OSS\OssClient(
$_ENV['ALIYUN_OSS_ACCESS_KEY_ID'] ?? '',
$_ENV['ALIYUN_OSS_ACCESS_KEY_SECRET'] ?? '',
$_ENV['ALIYUN_OSS_ENDPOINT'] ?? ''
);
});
- Endpoint 必须带协议,如
https://oss-cn-hangzhou.aliyuncs.com;缺https://会导致 DNS 解析失败 - Bucket 名称不要拼在客户端里,上传时再传,方便多 Bucket 复用同一 client
- 密钥严禁出现在代码中,全部走
.env+$_ENV注入
上传前校验三件事,省掉 80% 的线上问题
用户扔来一个 .mp4 文件,不代表它就能直接进 OSS。OSS 对 object key 和元数据有隐性要求,漏检就会出现“上传成功但无法播放”“URL 打开是下载弹窗”等问题。
- 检查
$_FILES['file']['error'] === UPLOAD_ERR_OK,别只看是否非空 - 校验
mime_content_type($_FILES['file']['tmp_name'])是否在白名单内(如video/mp4、image/jpeg),防止伪造后缀 - object key 必须含合法后缀且不含控制字符,建议用
pathinfo($original_name, PATHINFO_EXTENSION)拼接随机前缀,例如s3/7a2f9d4e.mp4
最易忽略的是 Content-Type —— 它决定浏览器行为。私有 bucket 用 signUrl() 生成链接时,若没设对类型,签名 URL 仍会强制下载;公共 bucket 则直接返回错误 MIME,前端 video 标签黑屏无报错。



















