0

I am trying to create an API test function via AWS API Gateway and a Lambda function that is invoked via a Vue app with Axios. It is supposed to send a name and email from input elements. Every time I receive this error:

Access to XMLHttpRequest at '[API Gateway URL]' from origin 'http://localhost:8080' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: It does not have HTTP ok status.

I have enabled CORS on each step/resource in the API Gateway setup (per this article). Here is the code for the Vue component:

<template>
<div data-app>
        <div class="cell" id="testForm">
    {{responseMsg}}

       <label>Name</label>
       <input v-model="name" type="text" placeholder="Name">
       <label>Email Address</label>
       <input v-model="email" type="email" placeholder="Email Address">
       <button v-on:click="formFunction">Submit</button>
   
   </div>
</div>
</template>

<script>
import axios from 'axios';

export default {
    name: "formtest",
    data: function () {
        return {name: '',
        email: '',
        responseMsg: 'No response yet!'}
    },
    methods: {
        formFunction: function () {
            const formObj = {
                name: this.name,
                email: this.email
            }
            const reqURL = [API gateway URL];
            axios.post(reqURL, formObj)
    .then(response => {
        console.log(response);
        });

        }
    }
}

</script>

And here is my Lambda function:

exports.handler = async (event) => {
    const resString = 'Hello ' + event.name + ", your email address is " + event.email

    const response = {
        statusCode: 200,
         headers: {
            "Access-Control-Allow-Headers" : "Content-Type",
            "Access-Control-Allow-Origin": "*",
            "Access-Control-Allow-Methods": "OPTIONS,POST,GET"
        },
        body: resString,
    };
    return response;
};

What could I be doing wrong here?

  • Have u enable CORS for POST method in the server? – Viresh Mathad Dec 21 '20 at 16:30
  • have u tried sending the content type header? axios.defaults.headers.post['Content-Type'] ='application/x-www-form-urlencoded'; – Viresh Mathad Dec 21 '20 at 16:33
  • Check to make sure that the URL that is setup in API Gateway is the exact same URL that Axios is calling. Because the first request out of Axios is the CORS pre-flight request, if you are calling the wrong URL you will get a CORS failure error instead of a 404 not found error, for example. – hvaughan3 Dec 21 '20 at 16:40
  • Although it should happen automatically, if you create the resources in the AWS console, check that there is also an `OPTIONS` method configured. – Jens Dec 21 '20 at 17:20

1 Answers1

0

Notes:

  • My answer below was written to a problem (mine) like yours but with a route that needs Authentication (Cognito for example). In any case, the solution applies to your case too.
  • If I am not mistaken, your axios request has/request JSON data-type and that makes it a "non-simple request" (more on a link below).
  • Your problem is NOT related with Vue or Axios (I am using the same). enter image description here

ANSWER

Under certain conditions, a POST/GET request becomes a non-simple request.

That non-simple request will do a pre-flight OPTIONS request to the same destination to verify some stuff, and if happy with the response, then do your original request.

Why is an OPTIONS request sent and can I disable it?

If the Path (API_url/private) needs Authentication, the OPTIONS request will fail and you will never* manage to get your POST/GET request through.

If the path does not need Authentication but the response to OPTIONS does not provide a CORS response, the OPTIONS request will fail and you will never* manage to get your POST/GET request through.

* If using something running on the browser, because the browser does care very much about CORS. If you are outside the browser (using 'curl' for example) your request will work because it does not care about CORS responses/parameters.

The solution is simple but not obvious:

If you have a

route       verb            Authentication      integration
/private    POST/GET        yes                 lambda-private

Then you need to create an extra

route       verb            Authentication      integration
/private    POST/GET        yes                 lambda-private
/private    OPTIONS         no                  lambda-CORS-response

So your pre-flight request will get a nice response and the POST/GET request will hit your desired destination.

These are the integrations (with different lambdas)

enter image description here

And here the Authorizers (only POST has Authorizer)

enter image description here

If you do this, it will attend all OPTIONS regardless of the route (not verified)

route       verb            Authentication      integration
/{proxy+})  OPTIONS         no                  lambda-CORS-response

This is somehow explained here, but they don't say that you need to create 'an extra lambda function' to give a response to that route / verb.

https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-cors.html https://docs.aws.amazon.com/apigateway/latest/developerguide/how-to-cors.html

Routes https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-routes.html#http-api-develop-routes.evaluation

Until I got to the solution I explored other options. Below are my findings. More than happy to correct the information if someone finds it to be wrong (claims need to be backed up somehow).


Q: I am using a "HTTP API" (AWS). Do I need to switch to "REST API" to resolve this?

A: At some stage I thought so. But no, just follow the instructions above.

However, "REST API" have more options (they are also more costly) and maybe you don't need to do what is described above. If someone has insights about that I'll be happy to update this part. However, having more options may also mean 'more complexity on the setup'.


Q: So what is the CORS configuration on the API for if I need to provide the CORS responses myself?

A: Apparently only for '200 type' responses. -> https://enable-cors.org/server_awsapigateway.html

My functions only work when I provide the CORS response myself.


Q: Can I avoid the pre-fligh OPTIONS request by submitting my data inside a GET instead of a POST

A: NO, it will happen anyway if your request meets the conditions to be a non-simple request.


Q: Why my POST/GET request with Axios within my app/webpage fails complaining about CORS but 'curl' will run just fine.

A: 'curl' Does not care about CORS, the browser does and very much. At least 'curl' allows you to know that 'something is working' but that you have some extra work to get it fully right.

Rub
  • 790
  • 8
  • 15