1. 一张 S3 图片链接,为什么经常在“公开”这一步翻车
先把这个需求拆开看:往 Amazon S3 上传一张图,让这张图能通过链接被任何人直接打开,看起来只是个发布操作,其实背后同时牵扯到“上传”“公开访问配置”“Content-Type 元数据”三件事。我经常看到一些同行兴冲冲地把图片传上去,复制了对象 URL 发给别人,结果对面点开是一段 XML,上面写着 AccessDenied。这不是网速问题,也不是 AWS 抽风,而是默认状态下 S3 几乎把所有“所有人都能读”的通道都堵死了。
AWS 把“公开”做成了默认要主动申请的状态,原因不难理解:企业或个人常把 S3 当私有文件库,如果一传上去就全世界可读,那每次上传身份证扫描件简直是灾难。但从新手的角度讲,去控制台找“公开”开关时,能明显感觉到有些入口很隐蔽,有些设置相互牵连,比如桶策略、对象 ACL、Block Public Access 这些概念混在一次,容易让人抓瞎。
这篇文章我打算完整走一遍从创建桶到直链可访问的流程,包含 AWS 管理控制台操作和命令行 CLI 操作两套方式。图片上传后能直接被浏览器打开而不是被强制下载,是这里要重点解决的问题。只要按链路排查,二十分钟内基本能结束战斗。
1.1 先看懂 S3 的“公开链路”到底由哪些开关控制
S3 里一个对象要想被匿名访问,大致要满足下面这串条件:
- 存储桶的“阻止公共访问(Block Public Access)”不能被全部打开,或者说至少得允许公开策略生效。
- 存储桶策略或者对象 ACL 中,必须有一条允许
s3:GetObject的规则,Principal 要包含匿名用户。 - 存储桶所在账号如果启用了账号级别的 Block Public Access,同样会覆盖桶上的设置。
- 对象本身不能被加密密钥拦截,否则即使权限允许,浏览器也会拿不到数据。用 S3 默认的 SSE-S3 加密通常没有这个问题。
很多人只修改了其中某一步,自然打不开。比如桶策略写得没问题,但 Block Public Access 没关,那么访问时会直接被系统拒绝。
另外一个容易被忽略的点是“能读文件”和“能在浏览器里显示”并不是一回事。 S3 在返回图片时,会带上一个 Content-Type 响应头,比如 image/jpeg,浏览器看到这个头才会把内容当成图片渲染出来。如果上传时没有正确写入这个元数据,或者 Content-Disposition 被设置成了附件,那么即使用户权限正常,浏览器也可能下载到本地而不是直接打开。这就是为什么有些人的图片是“Access Denied”,有些人的图片是“直接下载”。
1.2 最终目标状态:公有读、私有写
关于 Public 公开,我们要达到的并不是把整个桶的可见性完全暴露出去。更推荐的状态是:匿名用户能读取指定前缀下的对象,但只有你或者授权的 IAM 用户能写入、删除、改配置。
这种模式可以概括为“公有读、私有写”。标题里的 Public 指的是 Read,并不是对存储桶管理操作开放权限。如果你在写桶策略时只给了 s3:GetObject,而没有开放 s3:ListBucket,那别人就没法通过接口遍历你的文件名;他必须知道某个具体的对象 URL 才能访问。这样做既满足了图片直链需求,又不至于让整个目录结构裸奔,安全等级会高很多。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 动手前把这几件事先定下来
2.1 存储桶命名和区域选择
S3 存储桶名字是全局唯一的,也就是说全 AWS 的客户共用同一个命名空间,不能叫 my-image-bucket 这种太常见的名字,大概率会被提示重名。我习惯在名字后面加上业务缩写和日期,比如 myteam-image-backup-2025,看着不优雅但很实用,也方便审计。
区域选择上,通常建议选离你的访问用户更近的区域。如果主要给同事或内部系统用,选你当前 VPC 相近的区域即可。如果给外部网站引用,建议考虑访问延迟和流量成本后再定,不必盲目选择热门区域。同区域间的 AWS 服务传输数据一般不会额外收流量费,跨区域则麻烦一些。
2.2 目录结构决定了后续策略好不好写
新建桶时不用急着创建文件夹,但上传前要定好目录规划。我个人的习惯是:需要公开的资源统一放进 public/ 前缀下,内部私有文件放到 private/ 或直接放其他桶。
这样做最大的好处是,桶策略可以直接写成只对 public/* 生效。以后即使有人误操作,把某些本该私有的对象传到根目录,也不会因为一条通配策略而被公开。权限配置中“最小粒度”这件事不能
