当前位置: 首页 > news >正文

CloudFront + Lambda@Edge 实战:双函数架构实现失败请求记录与异步重放完整方案

本文基于亚马逊云科技官博最新发布的技术方案,深入分析如何在不修改源站代码的前提下,利用 Amazon CloudFront 的 Lambda@Edge 能力完整记录失败请求并支持异步补数重放。

亚马逊云科技官博今天(3/31)发了一篇实战文章:用 Amazon CloudFront 双 Lambda@Edge 架构,在不改源站代码的前提下,完整记录被拦截和出错的请求(含 headers 和 body),然后异步重放补数。

这思路挺巧的,拆解一下。

先说痛点

做过 CDN + WAF 架构的都遇到过这几个问题:

  1. WAF 误杀:安全规则有时候拦的是正常业务请求,事后想找回原始请求,只有日志里的 URL 和 status code,body 没了
  2. 源站临时挂了:返回 500/502 的请求,CDN 层面只能看到"失败了",具体请求内容不知道
  3. 改源站不现实:源站可能在第三方云、可能是供应商的系统、可能没代码权限

传统方案要么改源站代码加中间件,要么用 CloudFront 实时日志(但不含 body)。这次的方案在 CDN 层解决了所有问题。

架构核心:双 Lambda@Edge

整个方案用两个 Lambda@Edge 函数配合:

请求 → CloudFront → [WAF 检查]↓ 通过origin-request Lambda@Edge(把 request body 存进自定义 header)↓源站处理↓origin-response Lambda@Edge(检测 4xx/5xx → 记录完整请求到 CloudWatch Logs)↓CloudWatch Logs → Kinesis Data Firehose → S3

关键设计:

1. body 怎么传递

Lambda@Edge 在 origin-request 阶段能拿到 request body,但 origin-response 阶段拿不到。所以第一个函数把 body 塞进自定义 header X-Original-Body,第二个函数从 header 里读出来。

// origin-request Lambda@Edge
exports.handler = async (event) => {const request = event.Records[0].cf.request;if (request.body && request.body.data) {// 把 body 存进自定义 headerrequest.headers['x-original-body'] = [{key: 'X-Original-Body',value: request.body.data}];}return request;
};

2. 只记失败的

origin-response 阶段检查状态码,只有 4xx/5xx 才触发记录逻辑。成功请求零开销。

// origin-response Lambda@Edge
exports.handler = async (event) => {const response = event.Records[0].cf.response;const request = event.Records[0].cf.request;const status = parseInt(response.status);if (status >= 400) {const failedRequest = {timestamp: new Date().toISOString(),uri: request.uri,method: request.method,headers: request.headers,body: request.headers['x-original-body'] ? request.headers['x-original-body'][0].value : null,responseStatus: status};// 写入 CloudWatch Logsconsole.log(JSON.stringify(failedRequest));}return response;
};

3. 日志怎么归档

Lambda@Edge 的日志自动进 Amazon CloudWatch Logs,加个 Subscription Filter 把日志投递到 Amazon Kinesis Data Firehose,再落到 Amazon S3。整条链路全 Serverless,不用管服务器。

# CloudFormation 片段
Resources:LogSubscription:Type: AWS::Logs::SubscriptionFilterProperties:DestinationArn: !GetAtt DeliveryStream.ArnFilterPattern: '"failedRequest"'LogGroupName: !Ref LambdaLogGroupDeliveryStream:Type: AWS::KinesisFirehose::DeliveryStreamProperties:S3DestinationConfiguration:BucketARN: !GetAtt FailedRequestsBucket.ArnBufferingHints:IntervalInSeconds: 60SizeInMBs: 5

WAF 拦截的请求怎么办

被 AWS WAF 拦截的请求根本到不了 origin-request 阶段。但 WAF 自己有日志,包含 headers 和 body 前 8KB。同样通过 CloudWatch Logs → Kinesis → S3 归档。

两条路径最终汇聚到同一个 S3 桶,补数脚本从 S3 读取后统一处理。

补数重放脚本

import json
import boto3
import requestss3 = boto3.client('s3')def replay_failed_requests(bucket, prefix, target_url):"""从 S3 读取失败请求日志并重放"""paginator = s3.get_paginator('list_objects_v2')for page in paginator.paginate(Bucket=bucket, Prefix=prefix):for obj in page.get('Contents', []):response = s3.get_object(Bucket=bucket, Key=obj['Key'])for line in response['Body'].read().decode().split('\n'):if not line.strip():continuerecord = json.loads(line)# 重放请求replay_response = requests.request(method=record['method'],url=f"{target_url}{record['uri']}",headers={k: v[0]['value'] for k, v in record['headers'].items()if k.lower() not in ('host', 'x-original-body')},data=record.get('body'))print(f"重放 {record['uri']}: {replay_response.status_code}")

成本分析

这方案的成本很可控:

组件 计费方式 估算(月 100 万请求,1% 失败率)
Lambda@Edge 按调用次数 + 执行时间 origin-request 处理所有请求,origin-response 只记失败的
CloudWatch Logs 按数据量 只有失败请求产生日志
Kinesis Data Firehose 按数据量 和日志量成正比
S3 存储 + 请求 日志文件通常很小

1% 失败率意味着每月只记录 1 万条请求,日志数据量可能就几十 MB。

实际用这个方案的场景

除了官博提到的 WAF 误杀和源站故障,还有几个常见场景:

  1. API 网关限流补偿:前端 CDN 层限流返回 429,记录被限的请求,低峰期重放
  2. 灰度发布回滚:新版本出 bug 导致 500,记录这段时间的请求,回滚后重放
  3. 跨云架构调试:源站在其他云上,出了问题想在亚马逊云科技侧看完整请求信息

用 OpenClaw 做运维自动化的话,可以写个 Skill 定期扫描 S3 里的失败请求日志,自动判断是否需要重放、通知值班人员、或者直接执行重放脚本。

几个注意点

  1. body 大小限制:Lambda@Edge 的 request body 默认上限 1MB(可调到 40KB 在 viewer-request,1MB 在 origin-request)。超大 body 需要截断
  2. 性能影响:origin-request 阶段给所有请求加了一次 header 操作,延迟增加约 1-5ms
  3. 安全考虑:存储了完整请求 body,可能包含敏感数据。S3 桶必须加密,设置生命周期策略自动清理
  4. 区域限制:Lambda@Edge 只能部署在 us-east-1,但会自动复制到全球边缘节点

亚马逊云科技官博原文:https://aws.amazon.com/cn/blogs/china/based-on-amazon-cloudfront-lambda-edge-implement/
Amazon CloudFront:https://aws.amazon.com/cn/cloudfront/
AWS Lambda@Edge:https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/lambda-at-the-edge.html
OpenClaw:https://github.com/openclaw/openclaw

http://www.jsqmd.com/news/570152/

相关文章:

  • 璀璨星河Starry Night部署教程:Python3.9+Diffusers环境完整配置
  • 文墨共鸣作品分享:中文食品标签‘零添加’‘无添加’‘不添加’语义等效性验证
  • PyTorch 3.0 DDP + torch.compile混合训练面试通关手册:涵盖Graph Break诊断、Shard策略冲突、以及3种反模式现场复现
  • 2026年西安有名的家装公司排行榜,西安芭宝整装装修公司排第几 - mypinpai
  • 卡牌设计革命:如何用CardEditor批量生成桌游卡牌效率提升300%
  • 豆包API+腾讯云COS实战:手把手教你打造智能图床(含完整代码)
  • 5分钟掌握B站视频下载:免费获取大会员4K高清内容的完整方案
  • Phi-4-mini-reasoning在C语言项目中的调用接口设计与实现
  • 遗传算法(GA)调参实战:以Scikit-learn模型为例,手把手教你自动化超参数搜索
  • 英雄联盟回放分析终极指南:ROFL-Player完整教程
  • 乙巳马年春联生成终端多场景落地:营销/教育/政务/文创四大应用矩阵
  • 解密Twitter风控参数:x-client-transaction-id的生成机制与逆向思考
  • 长沙 GEO 优化公司实测:本地场景适配与转化效率评测 - 亿仁imc
  • 说说西安比较好的家装企业,陕西芭宝整装装饰装修设计有限公司靠谱吗? - 工业设备
  • Qwen3-TTS语音合成案例分享:多语言合成效果展示
  • 2026 年山东长岛渔家乐口碑推荐榜单:长岛民宿、南岛民宿、北岛民宿哪家好,住宿选择全指南 - 海棠依旧大
  • 从零开始:roLabelImg安装与OBB旋转框标注实战指南
  • 长沙网络推广服务商评测:AI赋能与精准获客能力实测 - 亿仁imc
  • 解锁本地图片检索:ImageSearch的千万级图库秒级查找指南
  • Pixel Dimension Fissioner 游戏素材生成实践:快速创建2D像素风与概念原画
  • Phi-4-Reasoning-Vision代码实例:TextIteratorStreamer流式解析实现
  • 软件设计师学习
  • 从IIS用户到System:手把手教你用MSF和WESng搞定老旧Windows服务器提权
  • 2026年西安家装专业企业哪家好,知名品牌企业推荐 - 工业品网
  • ReplaceItems:4个颠覆级技巧让设计师效率提升8倍
  • 从服务激活到角色授权:完整搭建 SAP Fiori Launch Page 的实战指南
  • 箭头函数继承外层 this 详解
  • Gemini 3.1镜像深度推理实战:解构多模态长视频理解与结构化知识抽取
  • FPGA数字钟课程设计还能这么玩?从基础功能到智能扩展(附完整工程文件)
  • DeOldify企业级应用:构建自动化老照片修复平台