如何创建适配CloudFront与AWS API Gateway WebSocket的SAM模板
适配CloudFront与API Gateway WebSocket的SAM实现方案
核心配置避坑要点
- WebSocket协议依赖HTTP/1.1升级请求与HTTP/2传输,CloudFront必须开启全量HTTP方法(GET/POST/PUT/PATCH/DELETE/OPTIONS/HEAD),分发配置强制选
http2版本 - API Gateway WebSocket源必须使用
AllViewerExceptHost托管源请求策略,禁止透传Host头,否则会触发API Gateway域名校验403;缓存策略必须选CachingDisabled托管策略,所有查询参数、请求头、Cookie全量透传,不能丢Sec-WebSocket-Key/Upgrade/Connection这类握手必需头 - CloudFront的路径匹配规则必须覆盖WebSocket API的部署阶段路径,不要尝试给WebSocket路由加自定义路径改写,CloudFront Functions/Edge@AWS逻辑很容易篡改升级头导致握手失败
- 给API Gateway源配置专用的OAC(源访问控制),签名协议选sigv4,签名行为选始终签名,避免API端点公网暴露
可直接复用的SAM模板
AWSTemplateFormatVersion: '2010-09-09' Transform: AWS::Serverless-2016-10-31 Description: CloudFront + API Gateway WebSocket SAM deployment template Resources: # WebSocket API 核心定义 AppWebSocketApi: Type: AWS::ApiGatewayV2::Api Properties: Name: AppWebSocketService ProtocolType: WEBSOCKET RouteSelectionExpression: "$request.body.action" # 示例$connect路由与Lambda集成,其余$disconnect/$default/自定义路由可按相同结构扩展 ConnectRoute: Type: AWS::ApiGatewayV2::Route Properties: ApiId: !Ref AppWebSocketApi RouteKey: "$connect" Target: !Join [ '/', [ 'integrations', !Ref ConnectIntegration ] ] ConnectIntegration: Type: AWS::ApiGatewayV2::Integration Properties: ApiId: !Ref AppWebSocketApi IntegrationType: AWS_PROXY IntegrationUri: !Sub arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${WsConnectHandler.Arn}/invocations # WebSocket 部署阶段 WsProdStage: Type: AWS::ApiGatewayV2::Stage Properties: ApiId: !Ref AppWebSocketApi StageName: prod AutoDeploy: true # API Gateway 专用源访问控制 WsOriginOac: Type: AWS::CloudFront::OriginAccessControl Properties: OriginAccessControlConfig: Name: WsApiOac OriginAccessControlOriginType: apigateway SigningBehavior: always SigningProtocol: sigv4 # CloudFront 分发配置 CdnDistribution: Type: AWS::CloudFront::Distribution Properties: DistributionConfig: Enabled: true HttpVersion: http2 PriceClass: PriceClass_100 DefaultCacheBehavior: TargetOriginId: StaticAssetOrigin ViewerProtocolPolicy: redirect-to-https CachePolicyId: 658327ea-f89d-4fab-a63d-7e88639e58f6 # 托管CachingOptimized策略,用于静态资源 CacheBehaviors: # WebSocket专属缓存行为 - PathPattern: "prod/*" TargetOriginId: WebSocketApiOrigin ViewerProtocolPolicy: https-only AllowedMethods: GET,HEAD,OPTIONS,PUT,PATCH,POST,DELETE CachePolicyId: 4135ea2d-6df8-44a3-9df3-4b5a84be39ad # 托管CachingDisabled策略,禁止缓存WebSocket请求 OriginRequestPolicyId: b689b0a8-53d0-40ab-baf2-68738e2966ac # 托管AllViewerExceptHost策略 Origins: - Id: WebSocketApiOrigin DomainName: !Sub "${AppWebSocketApi}.execute-api.${AWS::Region}.amazonaws.com" OriginPath: "" OriginAccessControlId: !Ref WsOriginOac CustomOriginConfig: HTTPSPort: 443 OriginProtocolPolicy: https-only OriginSSLProtocols: [TLSv1.2] # 静态资源源(如S3站点)可按需求自行补充 - Id: StaticAssetOrigin # 此处替换为你自己的静态源配置 DomainName: example-bucket.s3.amazonaws.com CustomOriginConfig: HTTPSPort: 443 OriginProtocolPolicy: https-only OriginSSLProtocols: [TLSv1.2] # 示例连接处理Lambda WsConnectHandler: Type: AWS::Serverless::Function Properties: Runtime: nodejs20.x Handler: index.handler InlineCode: | exports.handler = async (event) => { // 自定义连接鉴权逻辑写在这里 return { statusCode: 200 }; };
部署与排错流程
- 模板编写完成后,在项目根目录执行
sam build构建资源,再执行sam deploy --guided跟着引导完成首次部署,后续更新直接执行sam deploy即可 - 部署完成后,用
wss://<CloudFront分配的域名>/prod作为连接地址测试WebSocket连通性,不要直接调用API Gateway的默认公网端点 - 常见问题排查:
握手返回403:先检查源请求策略是否透传了Host头,再核对OAC签名区域与API部署区域是否一致,最后确认CloudFront已开启全量HTTP方法
连接建立成功但发送消息立即断连:检查WebSocket路径对应的缓存策略是否关闭了缓存,是否有边缘计算逻辑篡改了Upgrade/Connection头
请求返回404:检查CloudFront路径匹配规则是否正确覆盖WebSocket的阶段路径,确认路径中已携带部署阶段名(示例中为prod)
内容的提问来源于stack exchange,提问作者Ben Mora
相关产品推荐
相关产品推荐

