CORS与API网关生存指南 - 无服务器架构
无服务器架构中最受欢迎的应用场景之一。通过无服务器架构,您可以构建一个简单且可扩展的后端,同时避免繁重的运维工作。然而,在实现过程中,CORS(跨域资源共享)问题可能会成为一个常见的挑战。
快速指南:如何解决无服务器架构中的 CORS 问题
如果您想快速解决无服务器应用中的 CORS 问题,可以按照以下步骤操作:
-
返回 CORS 标头
在响应中添加以下关键 CORS 标头:
Access-Control-Allow-OriginAccess-Control-Allow-Credentials
示例代码如下:
module.exports.getProduct = (event, context, callback) => {
const product = retrieveProduct(event);
const response = {
statusCode: 200,
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Credentials': true,
},
body: JSON.stringify({ product: product }),
};
callback(null, response);
};
module.exports.createProduct = (event, context, callback) => {
const product = createProduct(event);
const response = {
statusCode: 200,
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Credentials': true,
},
body: JSON.stringify({ product: product }),
};
callback(null, response);
};
-
配置自定义授权器
如果您使用了自定义授权器,需要在
serverless.yml文件的resources块中添加以下 CloudFormation 配置:Resources: GatewayResponseDefault4XX: Type: "AWS::ApiGateway::GatewayResponse" Properties: ResponseParameters: gatewayresponse.header.Access-Control-Allow-Origin: "'*'" gatewayresponse.header.Access-Control-Allow-Headers: "'*'" ResponseType: DEFAULT_4XX RestApiId: Ref: 'ApiGatewayRestApi'
理解 CORS 飞行前请求
什么是飞行前请求?
当浏览器发起非“简单请求”时,会先发送一个 OPTIONS 方法的飞行前请求,以确认目标资源是否支持跨域请求。目标资源会返回允许的 HTTP 方法和标头等信息。
浏览器何时发送飞行前请求?
以下情况会触发飞行前请求:
- 使用
PUT或DELETE方法。 Content-Type标头不属于以下类型之一:application/x-www-form-urlencodedmultipart/form-datatext/plain
- 请求包含自定义标头(如身份验证标头)。
如何处理飞行前请求?
在无服务器架构中,您可以通过在 API 网关的端点中配置 OPTIONS 方法来处理飞行前请求。在 serverless.yml 文件中,添加以下配置:
functions:
yourFunction:
handler: handler.yourFunction
events:
- http:
path: your-path
method: get
cors: true
此配置将自动为 API 网关启用 CORS 支持,并允许所有域访问。如果需要更高级的自定义,可以指定允许的域和标头。
使用无服务器框架处理 CORS
在无服务器框架中,您需要确保每个跨域请求的响应中都包含以下标头:
Access-Control-Allow-OriginAccess-Control-Allow-Credentials(如果使用了 Cookie 或其他身份验证)
以下是一个示例代码片段,展示如何在 handler.js 文件中添加这些标头:
const response = {
statusCode: 200,
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Credentials': true,
},
body: JSON.stringify({ message: 'Success' }),
};
如果您的函数包含多个逻辑路径,手动添加这些标头可能会变得繁琐。幸运的是,有一些工具可以简化这一过程,例如 Middy 中间件库。
带有自定义授权器的 CORS 配置
当自定义授权器拒绝请求时,默认情况下不会返回 CORS 标头,这可能导致客户端浏览器无法正确解析响应。为了解决这一问题,您可以在 API 网关中添加自定义 GatewayResponse:
Resources:
GatewayResponseUnauthorized:
Type: "AWS::ApiGateway::GatewayResponse"
Properties:
ResponseParameters:
gatewayresponse.header.Access-Control-Allow-Origin: "'*'"
ResponseType: UNAUTHORIZED
RestApiId:
Ref: 'ApiGatewayRestApi'
CORS 与 Cookie 凭据
如果您的应用需要支持 Cookie 凭据,可以通过以下两种方式实现:
-
固定来源
如果只有一个固定的来源,可以直接在 Lambda 函数的响应中硬编码允许的来源:
headers: { 'Access-Control-Allow-Origin': 'https://example.com', 'Access-Control-Allow-Credentials': true, } -
动态来源
如果有多个来源,可以动态检查请求头中的
Origin,并根据允许的来源列表返回相应的标头:
const allowedOrigins = ['https://example1.com', 'https://example2.com'];
const origin = event.headers.origin;
const response = {
statusCode: 200,
headers: {
'Access-Control-Allow-Origin': allowedOrigins.includes(origin) ? origin : 'null',
'Access-Control-Allow-Credentials': true,
},
body: JSON.stringify({ message: 'Success' }),
};
总结
CORS 问题虽然复杂,但通过正确的配置和工具支持,可以大大简化处理过程。在无服务器架构中,您可以通过以下步骤高效地解决 CORS 问题:
- 在响应中添加必要的 CORS 标头。
- 配置 API 网关的
OPTIONS方法以处理飞行前请求。 - 使用工具库(如 Middy)简化标头管理。
- 针对自定义授权器和 Cookie 凭据采取额外的配置措施。
通过这些方法,您可以轻松应对无服务器架构中的 CORS 挑战。
原文链接: https://www.serverless.com/blog/cors-api-gateway-survival-guide