1

We have created our AWS Lambda function using Spring Cloud function. This function returns APIGatewayProxyResponseEvent response. Sample below

{
    "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 uses Lambda proxy integration , and hence there is no option for response mappings. We have enabled CORS by using Actions on the console. This automatically adds the OPTIONS method where we have configured the 200 response with below headers

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'

The above steps are in sync with the AWS documentation AWS - How to CORS Lambda proxy

We deployed the API in a stage and are able to access it via Postman. On accessing from our web-application, which is currently on localhost we get CORS error.

In Network tab its visible that the preflight request (OPTIONS) returns 200 OK and the required CORS headers. However the actual GET call still fails , saying "CORS Error".

The issue is that APIGW is not copying the headers returned in the APIGatewayProxyResponseEvent object to final APIGW Response headers

Is this a known issue or am I missing something

Edit

Screen shot of APIGW lambda proxy

enter image description here

Screen shot from APIGW response (Testing from console)

enter image description here

Network tab in browser developer options showing preflight request successful

enter image description here

Edit2

Adding Console output enter image description here

Mayank Madhav
  • 429
  • 1
  • 7
  • 19
  • Well can you share a screenshot of both requests and responses? You say it returns headers and then say `APIGW is not copying the headers` – Ermiya Eskandary Oct 12 '21 at 13:25
  • Refer to my answer here - https://stackoverflow.com/a/69499631/4800344 – Ermiya Eskandary Oct 12 '21 at 13:26
  • If this is a proxy integration, you will have to specify the headers in code – Ermiya Eskandary Oct 12 '21 at 13:28
  • What is the actual error message you get in the browser? Also, because you likely don't need access to the values of `Access-Control-Allow-Methods` and `Access-Control-Allow-Origin` from JavaScript, you likely don't need that `Access-Control-Expose-Headers` header. – jub0bs Oct 12 '21 at 13:35
  • @ErmiyaEskandary, yes its a proxy integration and the lambda code is returning all the headers in the AWS defined response object APIGatewayProxyResponseEvent . – Mayank Madhav Oct 12 '21 at 13:58
  • @jub0bs , the preflight request succeeds and it returns the required http headers . However the actual GET call fails. There is no response data/headers shown in browser for this call . Only in the Status section it says "CORS error" – Mayank Madhav Oct 12 '21 at 14:02
  • 2
    What does it say in the console? @MayankMadhav – Ermiya Eskandary Oct 12 '21 at 14:24
  • 1
    What @ErmiyaEskandary said. Check out the Console tab in your browser. – jub0bs Oct 12 '21 at 14:43

1 Answers1

0

Edit 1

On checking the spring cloud milestone release, This issue has been addressed starting 3.2.0-M1 . (Currently available release is 3.1.5). Once this is released my previous approach of sending APIGatewayProxyResponseEvent as output will work just fine.

@Oleg Zhurakousky can confirm

Original Answer below : (almost a work around)

Got help from AWS support and understood that the response being returned from the Spring Cloud function was being modified. This in turn resulted in all the headers being encapsulated as part of Lambda response body.

My previous implementation of the function was

 @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;
        };
    }

I had to change it to below to make sure the headers are treated as http headers and not a part of the lambda response body

@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;
        };
    }

The actual entry point into Spring cloud function is org.springframework.cloud.function.adapter.aws.FunctionInvoker::handleRequest

Here while preparing response spring takes the returned value from the function as Message (org.springframework.messaging) Payload.

Hence In order to set http headers we need to return a Message<APIGatewayProxyResponseEvent> instead of APIGatewayProxyResponseEvent. Here we explicitly set our http headers in Message headers.

Mayank Madhav
  • 429
  • 1
  • 7
  • 19