【问题标题】:Spring Cloud Function AWS Lambda with proxy integration on APIGW : CORS issueSpring Cloud Function AWS Lambda 与 APIGW 上的代理集成:CORS 问题
【发布时间】:2021-12-01 01:30:43
【问题描述】:

我们已经使用 Spring Cloud 函数创建了 AWS Lambda 函数。此函数返回 APIGatewayProxyResponseEvent 响应。下面的示例

{
    "statusCode": 200,
    "headers": {
        "Access-Control-Expose-Headers": "Access-Control-Allow-Methods,Access-Control-Allow-Origin",
        "Access-Control-Allow-Origin": "*",
        "Access-Control-Allow-Methods": "OPTIONS,POST,GET",
        "Access-Control-Max-Age": "200",
        "Access-Control-Allow-Headers": "Content-Type,Access-Control-Request-Method,Access-Control-Request-Headers",
        "Content-Type": "application/json"
    },
    "multiValueHeaders": null,
    "body": "response Data json Body",
    "isBase64Encoded": false
}

APIGW 使用 Lambda 代理集成,因此没有响应映射选项。 我们已通过使用控制台上的操作启用了 CORS。这会自动添加 OPTIONS 方法,我们已经配置了带有以下标头的 200 响应

Access-Control-Max-Age          :   '200'   
Access-Control-Allow-Headers    :   'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'  
Access-Control-Expose-Headers   :   'Access-Control-Allow-Methods,Access-Control-Allow-Origin'  
Access-Control-Allow-Origin     :   '*' 
Access-Control-Allow-Methods    :   'GET,OPTIONS'

以上步骤与AWS文档AWS - How to CORS Lambda proxy同步

我们在一个阶段部署了 API,并且能够通过 Postman 访问它。从当前位于本地主机上的 Web 应用程序访问时,我们会收到 CORS 错误。

在“网络”选项卡中,可以看到预检请求 (OPTIONS) 返回 200 OK 和所需的 CORS 标头。但是实际的 GET 调用仍然失败,说“CORS 错误”。

问题在于 APIGW 没有将 APIGatewayProxyResponseEvent 对象中返回的标头复制到最终的 APIGW 响应标头

这是一个已知问题还是我遗漏了什么

编辑

APIGW lambda 代理的屏幕截图

APIGW 响应的屏幕截图(从控制台测试)

浏览器开发者选项中的网络标签显示预检请求成功

编辑2

添加控制台输出

【问题讨论】:

  • 你能分享一下请求和响应的截图吗?你说它返回标题然后说APIGW is not copying the headers
  • 在这里参考我的回答 - stackoverflow.com/a/69499631/4800344
  • 如果这是代理集成,您必须在代码中指定标头
  • 控制台中的内容是什么? @MayankMadhav
  • @ErmiyaEskandary 说了什么。查看浏览器中的“控制台”选项卡。

标签: amazon-web-services aws-lambda cors aws-api-gateway spring-cloud-function


【解决方案1】:

编辑 1

在检查 Spring Cloud 里程碑版本时,此问题已从 3.2.0-M1 开始解决。 (当前可用的版本是 3.1.5)。一旦发布,我之前发送 APIGatewayProxyResponseEvent 作为输出的方法就可以正常工作了。

@Oleg Zhurakousky可以确认

原始答案如下:(几乎可以解决)

从 AWS 支持获得帮助并了解从 Spring Cloud 函数返回的响应正在被修改。这反过来又导致所有标头都被封装为 Lambda 响应主体的一部分。

我之前的函数实现是

 @Bean
    public Function<APIGatewayProxyRequestEvent,APIGatewayProxyResponseEvent> testFunc2(){
        return event -> {
            System.out.println(event);
            APIGatewayProxyResponseEvent response = new APIGatewayProxyResponseEvent();
            Map<String,String> hdr = new HashMap<>();
            hdr.put("Access-Control-Allow-Origin","*");
            response.setHeaders(hdr);
            response.setStatusCode(HttpStatus.OK.value());
            response.setBody("Hello World!");
            return response;
        };
    }

我必须将其更改为以下内容,以确保标头被视为 http 标头而不是 lambda 响应正文的一部分

@Bean
    public Function<APIGatewayProxyRequestEvent, Message<APIGatewayProxyResponseEvent>> testFunc3(){
        return event -> {
            System.out.println(event);
            APIGatewayProxyResponseEvent response = new APIGatewayProxyResponseEvent();
            Map<String,Object> hdr = new HashMap<>();
            hdr.put("Access-Control-Allow-Origin","*");
            response.setStatusCode(HttpStatus.OK.value());
            response.setBody("Hello World!");
            Message<APIGatewayProxyResponseEvent> finalResponse = new GenericMessage<APIGatewayProxyResponseEvent>(response,hdr);
            System.out.println("Response prepared " +response);
            System.out.println("Final Response being returned " +finalResponse);
            return finalResponse;
        };
    }

Spring cloud 函数的实际入口是org.springframework.cloud.function.adapter.aws.FunctionInvoker::handleRequest

这里在准备响应时,spring 将函数的返回值作为 Message (org.springframework.messaging) Payload。

因此,为了设置 http 标头,我们需要返回一个 Message 而不是 APIGatewayProxyResponseEvent。这里我们在 Message headers 中明确设置我们的 http headers。

【讨论】:

    猜你喜欢
    • 2018-10-27
    • 2021-03-23
    • 2019-04-13
    • 2020-09-05
    • 1970-01-01
    • 2020-07-25
    • 1970-01-01
    • 1970-01-01
    • 2020-06-22
    相关资源
    最近更新 更多