Lambda Function URL对接静态前端时出现CORS请求失败问题求助
我配置了一个Lambda Function URL(地址为https://xxxx.lambda-url.us-east-1.on.aws/),使用Postman或curl可成功访问并获取响应,但在Netlify托管的静态网站前端通过XHR请求该地址时,出现以下CORS错误:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://xxxx.lambda-url.us-east-1.on.aws/. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing). Status code: 200.
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://xxxx.lambda-url.us-east-1.on.aws/. (Reason: CORS request did not succeed). Status code: (null).
我已通过Terraform配置该Lambda Function URL的CORS规则如下:
resource "aws_lambda_function_url" "contact-mailer-endpoint" { function_name = aws_lambda_function.lambda_ses_fn.function_name authorization_type = "NONE" cors { allow_credentials = true allow_methods = ["*"] allow_origins = ["*"] allow_headers = ["date", "keep-alive", "X-Requested-With", "Access-Control-Allow-Origin", "Origin"] expose_headers = ["date", "keep-alive", "X-Requested-With", "Access-Control-Allow-Origin", "Origin"] max_age = 0 } }
前端使用的XHR请求代码如下:
let xhr = new XMLHttpRequest() xhr.onreadystatechange = () => { if (xhr.readyState === 4){ if (xhr.status === 200){ ... } else { ... } } } xhr.open('POST', 'https://xxxx.lambda-url.us-east-1.on.aws/') xhr.setRequestHeader('Content-Type', 'application/json'); xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); xhr.setRequestHeader('Access-Control-Allow-Origin', '*'); xhr.setRequestHeader('Origin', 'https://site-i-am-currently-on.com'); //contains actual website url xhr.send(body)
控制台显示CORS策略已配置允许所有源(通配符*),为何仍出现CORS错误?
核心问题1:凭证允许与通配符源冲突
当CORS配置中allow_credentials = true时,浏览器的安全规则明确禁止Access-Control-Allow-Origin使用通配符*,必须指定具体的源域名。哪怕Terraform允许你这么配置,实际请求时浏览器会直接拦截响应,导致报错。
核心问题2:前端请求头设置错误
Access-Control-Allow-Origin是响应头:这个头由服务器返回给浏览器,不需要前端手动发送,添加这个请求头属于无效操作,还可能触发额外的预检校验。Origin无需手动设置:浏览器会自动根据当前页面域名生成这个请求头,手动指定可能导致服务器CORS校验不匹配。
修复步骤
调整Terraform的CORS配置
- 将
allow_origins从["*"]替换为你的Netlify网站实际域名,比如["https://site-i-am-currently-on.com"] - 如果不需要传递凭证(比如cookie、HTTP认证信息),可以将
allow_credentials设为false,此时允许继续使用*作为源
修改后的示例配置:
resource "aws_lambda_function_url" "contact-mailer-endpoint" { function_name = aws_lambda_function.lambda_ses_fn.function_name authorization_type = "NONE" cors { allow_credentials = true allow_methods = ["*"] allow_origins = ["https://site-i-am-currently-on.com"] // 替换为你的实际域名 allow_headers = ["Content-Type", "X-Requested-With"] // 只保留实际需要的请求头 expose_headers = [] // 根据实际需要暴露的响应头设置,不需要则留空 max_age = 3600 // 设置合理的预检缓存时长,减少重复请求 } }- 将
精简前端XHR代码
移除不必要的请求头,只保留业务需要的部分:let xhr = new XMLHttpRequest() xhr.onreadystatechange = () => { if (xhr.readyState === 4){ if (xhr.status === 200){ ... } else { ... } } } xhr.open('POST', 'https://xxxx.lambda-url.us-east-1.on.aws/') xhr.setRequestHeader('Content-Type', 'application/json'); xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); xhr.send(body)验证预检请求
通过浏览器开发者工具的Network面板,查看OPTIONS预检请求的响应头,确认Access-Control-Allow-Origin已设置为你的网站域名,Access-Control-Allow-Methods包含POST方法,确保所有配置生效。
内容的提问来源于stack exchange,提问作者Jared

