如何解决AWS Cloudfront for S3 支持的网站 + Rest API:错误 - MethodNotAllowed / 不允许针对此资源使用指定的方法
我有一个 AWS S3 支持的静态网站和一个 RestApi。我正在为静态网站和 RestApi 配置一个 Cloudfront distribution。我为 S3 源和 RestApi 源完成了 OriginConfigs。我正在使用 AWS CDK 在代码中定义基础设施。
本文采用的方法:https://dev.to/evnz/single-cloudfront-distribution-for-s3-web-app-and-api-gateway-15c3]
API 在相对路径 /r/<resourcename>
或 /r/api/<methodname>
下定义。例如,/r/Account
指的是 Account 资源,而 /r/api/Validate
指的是称为 Validate 的 rpc 样式方法(在本例中为 HTTP POST 方法)。实现资源方法的 Lambda 方法使用适当的 PREFLIGHT OPTIONS 进行配置,静态网站的 url 列在该资源的允许来源中。例如:/r/api/Validate
方法 lambda 有
exports.main = async function(event,context) {
try {
var method = event.httpMethod;
if(method === "OPTIONS") {
const response = {
statusCode: 200,headers: {
"Access-Control-Allow-Headers" : "*","Access-Control-Allow-Credentials": true,"Access-Control-Allow-Origin": website_url,"vary": "Origin","Access-Control-Allow-Methods": "OPTIONS,POST,GET,DELETE"
}
};
return response;
} else if(method === "POST") {
...
}
...
}
API 和网站部署良好。这是 CDK 部署代码片段。
const string api_domain = "myrestapi.execute-api.ap-south-1.amazonaws.com";
const string api_stage = "prod";
internal WebAppStaticWebsiteStack(Construct scope,string id,IStackProps props = null) : base(scope,id,props)
{
// The S3 bucket to hold the static website contents
var bucket = new Bucket(this,"WebAppStaticWebsiteBucket",new BucketProps {
PublicReadAccess = false,BlockPublicAccess = BlockPublicAccess.BLOCK_ALL,RemovalPolicy = RemovalPolicy.DESTROY,WebsiteIndexDocument = "index.html",Cors = new ICorsRule[] {
new CorsRule() {
AllowedHeaders = new string[] { "*" },AllowedMethods = new HttpMethods[] { HttpMethods.GET,HttpMethods.POST,HttpMethods.PUT,HttpMethods.DELETE,HttpMethods.HEAD },AllowedOrigins = new string[] { "*" }
}
}
});
var cloudfrontOAI = new OriginAccessIdentity(this,"CloudfrontOAI",new OriginAccessIdentityProps() {
Comment = "Allows cloudfront access to S3"
});
bucket.AddToResourcePolicy(new PolicyStatement(new PolicyStatementProps() {
Sid = "Grant cloudfront origin access identity access to s3 bucket",Actions = new [] { "s3:Getobject" },Resources = new [] { bucket.BucketArn + "/*" },Principals = new [] { cloudfrontOAI.GrantPrincipal }
}));
// The cloudfront distribution for the website
var distribution = new CloudFrontWebdistribution(this,"WebAppStaticWebsitedistribution",new CloudFrontWebdistributionProps() {
ViewerProtocolPolicy = ViewerProtocolPolicy.REDIRECT_TO_HTTPS,DefaultRootObject = "index.html",PriceClass = PriceClass.PRICE_CLASS_ALL,GeoRestriction = GeoRestriction.Whitelist(new [] {
"IN"
}),OriginConfigs = new [] {
new SourceConfiguration() {
CustomOriginSource = new CustomOriginConfig() {
OriginProtocolPolicy = OriginProtocolPolicy.HTTPS_ONLY,DomainName = api_domain,AllowedOriginSSLVersions = new OriginSslPolicy[] { OriginSslPolicy.TLS_V1_2 },},Behaviors = new IBehavior[] {
new Behavior() {
IsDefaultBehavior = false,PathPattern = $"/{api_stage}/r/*",AllowedMethods = CloudFrontAllowedMethods.ALL,CachedMethods = CloudFrontAllowedCachedMethods.GET_HEAD_OPTIONS,DefaultTtl = Duration.Seconds(0),ForwardedValues = new Cfndistribution.ForwardedValuesproperty() {
QueryString = true,Headers = new string[] { "Authorization" }
}
}
}
},new SourceConfiguration() {
S3OriginSource = new S3OriginConfig() {
S3BucketSource = bucket,OriginAccessIdentity = cloudfrontOAI
},Behaviors = new [] {
new Behavior() {
IsDefaultBehavior = true,//PathPattern = "/*",Compress = false,CachedMethods = CloudFrontAllowedCachedMethods.GET_HEAD_OPTIONS
}
},}
}
});
// The distribution domain name - output
var domainNameOutput = new CfnOutput(this,"WebAppStaticWebsitedistributionDomainName",new CfnOutputProps() {
Value = distribution.distributionDomainName
});
// The S3 bucket deployment for the website
var deployment = new BucketDeployment(this,"WebAppStaticWebsiteDeployment",new BucketDeploymentProps(){
Sources = new [] {Source.Asset("./website/dist")},DestinationBucket = bucket,distribution = distribution
});
}
bundle.js:67 POST https://mywebapp.cloudfront.net/r/api/Validate 405
bundle.js:67
<?xml version="1.0" encoding="UTF-8"?>
<Error>
<Code>MethodNotAllowed</Code>
<Message>The specified method is not allowed against this resource.</Message>
<Method>POST</Method>
<ResourceType>OBJECT</ResourceType>
<RequestId>xxxxx</RequestId>
<HostId>xxxxxxxxxxxxxxx</HostId>
</Error>
预期的流程是对 https://mywebapp.cloudfront.net/r/api/Validate 的 POST 调用(使用 fetch() api 进行)由 cloudfront 转发到 RestApi 后端。看起来 Cloudfront 正在这样做,但后端正在返回错误(根据错误消息)。
我错过了什么?我该怎么做?
解决方法
这是通过执行以下操作修复的:
- 移至 Distribution 构造(根据 AWS 文档,它是在接收最新更新时使用的构造)。
- 添加 CachePolicy 和 OriginRequestPolicy 以控制 Cookie 转发和标头转发
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。