news 2026/9/15 20:57:18

AWS CLI CloudFront update-distribution 命令实战:两种更新方式与 ETag 校验原理

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
AWS CLI CloudFront update-distribution 命令实战:两种更新方式与 ETag 校验原理

AWS CLI CloudFront update-distribution 命令实战:两种更新方式与 ETag 校验原理

【免费下载链接】aws-cliUniversal Command Line Interface for Amazon Web Services项目地址: https://gitcode.com/GitHub_Trending/aw/aws-cli

aws cloudfront update-distribution是修改 CloudFront 分发(Distribution)配置的核心命令,无论是调整默认根对象、禁用分发,还是批量改动缓存策略、源站与行为配置,都必须经由它提交。本指南以 awscli/examples/cloudfront/update-distribution.rst 为骨架,结合 aws-cli 仓库中该命令的定制实现与自动化测试,完整讲解两种更新方式(--default-root-object快捷参数与--distribution-configJSON 文件)、ETag/If-Match 乐观并发校验机制,以及配置整体替换(非合并)这一最容易踩坑的语义。

命令总览:update-distribution 在 CloudFront 生命周期中的位置

CloudFront 分发的完整生命周期大致为:create-distribution(创建)→get-distribution-config(读取当前配置与 ETag)→update-distribution(修改)→delete-distribution(删除,需先禁用)。其中update-distribution承担了“修改”这一环,对应 CloudFront API 中的PUT /2020-05-31/distribution/{Id}/config请求(见 service-2.json 中UpdateDistribution操作的http定义)。

从服务端模型看,该操作要求两个必填参数:Id(分发 ID,位于 URI 路径)与DistributionConfig(完整的分发配置结构),另有一个可选但强烈建议携带的IfMatch请求头(对应If-Match,见 UpdateDistributionRequest 定义)。每次成功更新都会返回新的ETag与完整的Distribution对象。

方式一:用 --default-root-object 快捷更新默认根对象

原文档的第一个示例展示了最典型的用法——只改一个字段:

aws cloudfront update-distribution \ --id EDFDVBD6EXAMPLE \ --default-root-object index.html

--default-root-object的值是当访问者请求根 URL 时 CloudFront 返回的对象(例如index.html)。这个参数之所以能“只改一个字段”,是因为 aws-cli 在底层替你完成了三步工作(实现位于 awscli/customizations/cloudfront.py 的UpdateDefaultRootObject类):

  1. 自动调用get_distribution_config(Id=...)拉取该分发的当前完整配置;
  2. 从响应中取出ETag并填入请求的IfMatch
  3. 将当前DistributionConfig原样作为请求体,只把DefaultRootObject覆盖为目标值。

这保证了“只改一个字段、其余配置全部保留”的效果。该类的帮助文本明确写道:“CLI will automatically make a get-distribution-config call to load and preserve your other settings.”(CLI 会自动发起 get-distribution-config 调用来加载并保留你的其他设置)。

执行成功后返回的内容如下(摘自 update-distribution.rst):

{ "ETag": "E2QWRUHEXAMPLE", "Distribution": { "Id": "EDFDVBD6EXAMPLE", "ARN": "arn:aws:cloudfront::123456789012:distribution/EDFDVBD6EXAMPLE", "Status": "InProgress", "LastModifiedTime": "2019-12-06T18:55:39.870Z", "InProgressInvalidationBatches": 0, "DomainName": "d111111abcdef8.cloudfront.net", "ActiveTrustedSigners": { "Enabled": false, "Quantity": 0 }, "DistributionConfig": { "CallerReference": "6b10378d-49be-4c4b-a642-419ccaf8f3b5", "Aliases": { "Quantity": 0 }, "DefaultRootObject": "index.html", "Origins": { "Quantity": 1, "Items": [ { "Id": "example-website", "DomainName": "www.example.com", "OriginPath": "", "CustomHeaders": { "Quantity": 0 }, "CustomOriginConfig": { "HTTPPort": 80, "HTTPSPort": 443, "OriginProtocolPolicy": "match-viewer", "OriginSslProtocols": { "Quantity": 2, "Items": [ "SSLv3", "TLSv1" ] }, "OriginReadTimeout": 30, "OriginKeepaliveTimeout": 5 } } ] }, "OriginGroups": { "Quantity": 0 }, "DefaultCacheBehavior": { "TargetOriginId": "example-website", "ForwardedValues": { "QueryString": false, "Cookies": { "Forward": "none" }, "Headers": { "Quantity": 1, "Items": [ "*" ] }, "QueryStringCacheKeys": { "Quantity": 0 } }, "TrustedSigners": { "Enabled": false, "Quantity": 0 }, "ViewerProtocolPolicy": "allow-all", "MinTTL": 0, "AllowedMethods": { "Quantity": 2, "Items": [ "HEAD", "GET" ], "CachedMethods": { "Quantity": 2, "Items": [ "HEAD", "GET" ] } }, "SmoothStreaming": false, "DefaultTTL": 86400, "MaxTTL": 31536000, "Compress": false, "LambdaFunctionAssociations": { "Quantity": 0 }, "FieldLevelEncryptionId": "" }, "CacheBehaviors": { "Quantity": 0 }, "CustomErrorResponses": { "Quantity": 0 }, "Comment": "", "Logging": { "Enabled": false, "IncludeCookies": false, "Bucket": "", "Prefix": "" }, "PriceClass": "PriceClass_All", "Enabled": true, "ViewerCertificate": { "CloudFrontDefaultCertificate": true, "MinimumProtocolVersion": "TLSv1", "CertificateSource": "cloudfront" }, "Restrictions": { "GeoRestriction": { "RestrictionType": "none", "Quantity": 0 } }, "WebACLId": "", "HttpVersion": "http1.1", "IsIPV6Enabled": true } } }

注意响应中的几个关键信号:

  • ETag:更新后的配置版本标识,下次再更新时必须使用它作为IfMatch
  • Status: "InProgress":配置修改后 CloudFront 正在向全球边缘节点传播新配置,属正常中间状态;
  • LastModifiedTime:本次配置变更的时间戳;
  • InProgressInvalidationBatches:正在进行的失效批次数(此处为 0,与失效操作无关)。

方式二:用 --distribution-config + --if-match 提交完整配置

update-distribution的原生语义是“提交一份完整的新配置”。原文档第二个示例演示了如何禁用一个分发——把 JSON 文件中Enabled字段设为false,再连同--if-match一起提交:

aws cloudfront update-distribution \ --id EMLARXS9EXAMPLE \ --if-match E2QWRUHEXAMPLE \ --distribution-config file://dist-config-disable.json

关于--if-match,文档特别强调:更新分发时必须用它提供分发的ETag;获取ETag的命令是 get-distribution-config(或get-distribution)。同时文档提示,禁用成功后即可用 delete-distribution 删除该分发——这也是 CloudFront 官方推荐的删除流程:先禁用、再删除。

dist-config-disable.json的完整内容如下(摘自 update-distribution.rst):

{ "CallerReference": "cli-1574382155-496510", "Aliases": { "Quantity": 0 }, "DefaultRootObject": "index.html", "Origins": { "Quantity": 1, "Items": [ { "Id": "amzn-s3-demo-bucket.s3.amazonaws.com-1574382155-273939", "DomainName": "amzn-s3-demo-bucket.s3.amazonaws.com", "OriginPath": "", "CustomHeaders": { "Quantity": 0 }, "S3OriginConfig": { "OriginAccessIdentity": "" } } ] }, "OriginGroups": { "Quantity": 0 }, "DefaultCacheBehavior": { "TargetOriginId": "amzn-s3-demo-bucket.s3.amazonaws.com-1574382155-273939", "ForwardedValues": { "QueryString": false, "Cookies": { "Forward": "none" }, "Headers": { "Quantity": 0 }, "QueryStringCacheKeys": { "Quantity": 0 } }, "TrustedSigners": { "Enabled": false, "Quantity": 0 }, "ViewerProtocolPolicy": "allow-all", "MinTTL": 0, "AllowedMethods": { "Quantity": 2, "Items": [ "HEAD", "GET" ], "CachedMethods": { "Quantity": 2, "Items": [ "HEAD", "GET" ] } }, "SmoothStreaming": false, "DefaultTTL": 86400, "MaxTTL": 31536000, "Compress": false, "LambdaFunctionAssociations": { "Quantity": 0 }, "FieldLevelEncryptionId": "" }, "CacheBehaviors": { "Quantity": 0 }, "CustomErrorResponses": { "Quantity": 0 }, "Comment": "", "Logging": { "Enabled": false, "IncludeCookies": false, "Bucket": "", "Prefix": "" }, "PriceClass": "PriceClass_All", "Enabled": false, "ViewerCertificate": { "CloudFrontDefaultCertificate": true, "MinimumProtocolVersion": "TLSv1", "CertificateSource": "cloudfront" }, "Restrictions": { "GeoRestriction": { "RestrictionType": "none", "Quantity": 0 } }, "WebACLId": "", "HttpVersion": "http2", "IsIPV6Enabled": true }

关键字段速查

字段作用示例值
CallerReference配置的唯一标识,更新时不可更改cli-1574382155-496510
Aliases备用域名(CNAME)列表{"Quantity": 0}
DefaultRootObject根请求返回的默认对象index.html
Origins源站定义,S3 源用S3OriginConfig,自定义源用CustomOriginConfigDomainName: "amzn-s3-demo-bucket.s3.amazonaws.com"
DefaultCacheBehavior默认缓存行为(TTL、HTTP 方法、转发策略等)MinTTL: 0, DefaultTTL: 86400, MaxTTL: 31536000
CacheBehaviors按路径匹配的附加缓存行为{"Quantity": 0}
CustomErrorResponses自定义错误响应{"Quantity": 0}
PriceClass价格等级,可选PriceClass_All/PriceClass_100/PriceClass_200PriceClass_All
Enabled是否启用分发,禁用需设为falsefalse
ViewerCertificate证书与 TLS 最低版本配置MinimumProtocolVersion: "TLSv1"
Restrictions地理限制RestrictionType: "none"
WebACLId关联的 WAF ACL ID""
HttpVersionHTTP 版本,示例从http1.1改到http2http2
IsIPV6Enabled是否启用 IPv6true

提交后的响应(摘自 update-distribution.rst)中,DistributionConfig.Enabled已变为false,且生成了新的ETag: "E9LHASXEXAMPLE"

{ "ETag": "E9LHASXEXAMPLE", "Distribution": { "Id": "EMLARXS9EXAMPLE", "ARN": "arn:aws:cloudfront::123456789012:distribution/EMLARXS9EXAMPLE", "Status": "InProgress", "LastModifiedTime": "2019-12-06T18:32:35.553Z", "InProgressInvalidationBatches": 0, "DomainName": "d111111abcdef8.cloudfront.net", "ActiveTrustedSigners": { "Enabled": false, "Quantity": 0 }, "DistributionConfig": { "CallerReference": "cli-1574382155-496510", "Aliases": { "Quantity": 0 }, "DefaultRootObject": "index.html", "Origins": { "Quantity": 1, "Items": [ { "Id": "amzn-s3-demo-bucket.s3.amazonaws.com-1574382155-273939", "DomainName": "amzn-s3-demo-bucket.s3.amazonaws.com", "OriginPath": "", "CustomHeaders": { "Quantity": 0 }, "S3OriginConfig": { "OriginAccessIdentity": "" } } ] }, "OriginGroups": { "Quantity": 0 }, "DefaultCacheBehavior": { "TargetOriginId": "amzn-s3-demo-bucket.s3.amazonaws.com-1574382155-273939", "ForwardedValues": { "QueryString": false, "Cookies": { "Forward": "none" }, "Headers": { "Quantity": 0 }, "QueryStringCacheKeys": { "Quantity": 0 } }, "TrustedSigners": { "Enabled": false, "Quantity": 0 }, "ViewerProtocolPolicy": "allow-all", "MinTTL": 0, "AllowedMethods": { "Quantity": 2, "Items": [ "HEAD", "GET" ], "CachedMethods": { "Quantity": 2, "Items": [ "HEAD", "GET" ] } }, "SmoothStreaming": false, "DefaultTTL": 86400, "MaxTTL": 31536000, "Compress": false, "LambdaFunctionAssociations": { "Quantity": 0 }, "FieldLevelEncryptionId": "" }, "CacheBehaviors": { "Quantity": 0 }, "CustomErrorResponses": { "Quantity": 0 }, "Comment": "", "Logging": { "Enabled": false, "IncludeCookies": false, "Bucket": "", "Prefix": "" }, "PriceClass": "PriceClass_All", "Enabled": false, "ViewerCertificate": { "CloudFrontDefaultCertificate": true, "MinimumProtocolVersion": "TLSv1", "CertificateSource": "cloudfront" }, "Restrictions": { "GeoRestriction": { "RestrictionType": "none", "Quantity": 0 } }, "WebACLId": "", "HttpVersion": "http2", "IsIPV6Enabled": true } } }

必须理解的三个核心语义

  1. 配置是整体替换,不是字段合并。服务端模型文档明确写道:"The values that you specify in an UpdateDistribution request are not merged into your existing configuration. Make sure to include all fields: the ones that you modified and also the ones that you didn't."(你在 UpdateDistribution 请求中指定的值不会与现有配置合并,必须包含所有字段——既包括你修改的,也包括未修改的)。因此凡是走--distribution-config路线,必须基于get-distribution-config的输出做增量修改,绝不能只提交想改的几个字段,否则其余配置会被清空或导致校验失败。

  2. CallerReference不可变更。模型文档明确指出"You can't change the value of CallerReference.",任何试图修改它的更新都会被拒绝。

  3. ETag 是乐观并发控制的关键IfMatch请求头携带当前配置的版本号(ETag),若在此期间配置被其他人修改过(ETag 不匹配),服务端会拒绝本次提交,从而避免“丢失更新”。这也是 aws-cli 在--default-root-object快捷模式下自动取 ETag 的原因——既简化了操作,也保证了并发安全。若发生版本冲突,模型错误列表中对应PreconditionFailedInvalidIfMatchVersion等错误。

两种方式的取舍与互斥约束

  • --default-root-object:适合“只改一个字段”的场景,CLI 自动完成 get-distribution-config → 合并 → 提交全流程,不会覆盖其他配置(源码见 UpdateDefaultRootObject)。
  • --distribution-config:适合批量修改或多个字段联动的场景,需要自行维护完整 JSON;建议通过file://前缀从文件加载(如--distribution-config file://dist-config-disable.json),避免超长命令行与转义问题。
  • 两者互斥:aws-cli 注册了operation-args-parsed.cloudfront.update-distribution事件,通过validate_mutually_exclusive_handler(['default_root_object'], ['distribution_config'])校验(见 cloudfront.py),同时指定两者会报错退出。

底层实现与测试验证

该命令的定制逻辑集中在 awscli/customizations/cloudfront.py,要点如下:

  • register()中为update-distribution挂载了两类事件:参数互斥校验(operation-args-parsed)与自定义参数注入(building-argument-table);
  • UpdateDefaultRootObject继承自CreateDefaultRootObject(后者用于create-distribution的同类快捷参数),但额外注入了“自动 get-distribution-config 并保留其他配置”的行为;
  • create_distributionupdate_distribution共用一套distribution_config_template()模板(CallerReferenceunique_string()生成,含时间戳与随机数,见 cloudfront.py)。

自动化测试 tests/functional/cloudfront/test_update_distribution.py 验证了四条关键行为,可作为理解语义的参考:

  1. --default-root-object index.html:mock 的get_distribution_config响应返回ETagDistributionConfig,最终请求参数包含DistributionConfig(含新DefaultRootObject)、IdIfMatch(值为 mock 的__etag__);
  2. --distribution-config:仍按原生方式直接透传配置结构;
  3. 同时指定两者:退出码 255,错误信息提示“cannot be specified when one of the following”(不可与其他参数同时指定);
  4. 不提供任何配置输入:退出码 255,参数校验失败。

常见错误与排查建议

报错方向触发场景建议
PreconditionFailed/InvalidIfMatchVersion--if-match的 ETag 过期或错误重新执行 get-distribution-config 获取最新 ETag 后重试
IllegalUpdate尝试修改CallerReference,或试图更新已删除/非活动分发保持CallerReference原值不变
InvalidDefaultRootObject默认根对象以/开头或为空传入不带前导斜杠的对象路径,如index.html
MissingBody/ 校验失败--distribution-config提交的 JSON 不完整或必填字段缺失基于get-distribution-config输出逐字段核对,补齐全部配置项
NoSuchDistribution分发 ID 不存在list-distributions核对 ID

结语

update-distribution是管理 CloudFront 分发配置的必经入口,其精髓在于三点:完整配置整体替换(不合并)、ETag/If-Match 并发控制(防覆盖)、CLI 快捷参数与原生 JSON 两种模式(按场景取舍)。需要临时改一个字段时,--default-root-object这类快捷参数会自动加载并保留现有配置;需要批量变更时,先get-distribution-config导出完整配置、修改后以file://JSON 提交,同时带上最新 ETag。掌握这两条路线,即可安全、可复现地完成 CloudFront 分发的日常运维。如需进一步了解配置导出,可对照阅读 get-distribution-config.rst;涉及分发的创建与删除,可参考 create-distribution.rst 与 delete-distribution.rst。

【免费下载链接】aws-cliUniversal Command Line Interface for Amazon Web Services项目地址: https://gitcode.com/GitHub_Trending/aw/aws-cli

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/15 20:56:42

两阶段鲁棒优化在微电网经济调度中的应用与Matlab实现

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/15 20:56:23

OpenCode-AI + Skill工具链:提升开发效率的智能编程方案

1. 为什么选择OpenCode-AI Skill?作为一名长期在Windows平台折腾开发环境的程序员,我最近被OpenCode-AI Skill这套工具链彻底征服了。它不仅仅是又一个AI编程助手,而是将代码补全、智能重构、自动化脚本执行等能力无缝整合进开发工作流的革…

作者头像 李华