最稳路径是用官方SDK github.com/aliyun/aliyun-oss-go-sdk/oss,但必须严格校验endpoint格式(纯https域名)、RAM子账号最小权限策略、显式设置超时参数,否则易出现上传卡死、403拒绝或跨区域失败。

直接用 oss.Client 初始化上传就行,但必须注意 endpoint、bucket、credentials 三者地域和网络类型(内网/外网)严格匹配,否则 PutObject 会卡住或报 signature does not match。
初始化 OSS Client 容易错配 endpoint 和 region
OSS 的 endpoint 不是通用域名,它绑定具体地域且区分内外网。比如杭州 bucket 的外网 endpoint 是 https://oss-cn-hangzhou.aliyuncs.com,内网是 http://oss-cn-hangzhou-internal.aliyuncs.com。用错会导致连接超时或签名失败。
- 确认 bucket 创建时选的地域(如
oss-cn-hangzhou),再查控制台「基本信息」页获取准确 endpoint - 如果 Gin 服务部署在阿里云 ECS 上,优先用内网 endpoint(协议为
http,非https),省流量、低延迟 -
oss.New的第一个参数必须是 endpoint 字符串,不能带/结尾,也不能拼接 bucket 名 - region 参数(如有)应与 endpoint 地域一致,SDK 通常从 endpoint 自动推导,显式传参反而容易出错
上传文件时 PutObject 的 key 必须不含 bucket 名
OSS 的 object key 就是文件在 bucket 内的路径,例如 uploads/avatar/abc.jpg。很多人误把 bucket 名拼进 key,写成 my-bucket/uploads/avatar/abc.jpg,结果上传成功但访问 404——因为实际存到了 my-bucket/my-bucket/uploads/... 下。
- key 是相对路径,
oss.PutObjectRequest构造时只传这个路径,不要加 bucket 前缀 - 生成 key 时建议用 UUID + 原扩展名,避免中文或特殊字符:
uuid.NewString() + filepath.Ext(originalName) - 若需分类存储,用目录前缀即可,如
images/、videos/,OSS 本身无真实目录结构,只是 key 的字符串前缀
前端直传必须配好 CORS 且签名有效期要合理
前端直传不经过 Gin 后端,而是由浏览器直连 OSS,所以必须提前在 bucket 控制台配置 CORS,否则会触发跨域拦截;同时后端签发的 policy 和 signature 一旦过期,前端上传直接失败,错误信息常为 InvalidAccessKeyId 或空响应。
- CORS 规则至少允许
PUT方法、Content-Type头、以及你的前端域名(别用*配置 origin,否则无法携带 credentials) - 签名有效期建议设为 30–60 秒,太短前端来不及发起请求,太长则安全风险上升
- 签名时的
policy必须包含expiration和conditions,其中bucket字段值必须和实际 bucket 名完全一致(大小写敏感) - 前端拿到 signature 后,要用
AccessKeyId而非AccessKeySecret发起请求,后者绝不能泄露到前端
删除文件前务必检查 URL 是否含 domain
oss.DeleteObject 接收的是 object key,不是完整 URL。如果传入的是类似 https://my-bucket.oss-cn-hangzhou.aliyuncs.com/uploads/123.jpg 这种带协议和域名的地址,会删错路径甚至静默失败。
- 统一约定:业务层保存的“文件路径”字段只存 key(如
uploads/123.jpg),不拼 domain - 生成可访问 URL 是单独逻辑:
client.Bucket.URL(key, expiration)或拼接https://<bucket>.<endpoint>/<key> - 删除操作前加日志打印 key,确认无协议、无域名、无重复前缀
真正麻烦的不是调用 SDK 函数,而是 endpoint 类型、key 格式、CORS 策略、URL 与 key 的边界这四点——它们散落在不同配置环节,出问题时现象相似(上传失败/404/签名无效),但根因完全不同。


















