aws / chalice

Python Serverless Microframework for AWS
Apache License 2.0
10.66k stars 1.01k forks source link

JavaScript Fetch API blocked by CORS policy due to gzip? #1336

Open MartijnHarmenzon opened 4 years ago

MartijnHarmenzon commented 4 years ago

I am running into a CORS error and can not seem to find out why. After testing I think it has something to do with either CORS, headers, app.api.binary_types.append("application/json"), or a combination. Can someone help? I have searched the web for a couple of hours, but can not seem to find the answer.

My Chalice app code:

from chalice import Chalice, Response
app = Chalice(app_name="myChaliceApp")
app.api.binary_types.append("application/json")
app.debug = True

@app.route("/some_test3", methods=["POST"], cors=True)
def some_test3():
    request = app.current_request
    data = request.json_body
    blob = json.dumps(data).encode("utf-8")
    payload = gzip.compress(blob)
    custom_headers = {"Content-Type": "application/json", "Content-Encoding": "gzip"}

    return Response(body=payload, status_code=200, headers=custom_headers)

My JavaScript code:

    const url = "https://xxxx.execute-api.eu-central-1.amazonaws.com/api/some_test3"

    const data = {
      Test: 3
    };

    fetch(url, {
        method: 'POST',
        body: JSON.stringify(data),
        headers: {
          'Content-Type': 'application/json',
          'Accept-Encoding': 'gzip'
        }
      })
      .then((response) => response.json())
      .then((data) => {
        console.log('Success:', data);
      })
      .catch((error) => {
        console.error('Error:', error);
      });
ricky-sb commented 4 years ago

What happens when you use the "Test" feature of API Gateway?

I've had similar issues before, and the CORS error is usually emanating from the API Gateway layer, instead of the Lamdba layer. By using the "Test" feature in the API Gateway, the Lambda function gets invoked directly. Set your headers to how you'd normally have it and take a look at the results.

Misza13 commented 4 years ago

I have the exact same problem, regardless whether it is a POST or GET method.

I have put a minimal repro under: https://github.com/Misza13/cors-gzip-repro

The line that breaks the solution (the way to gzip content is taken straight from Chalice tutorial) is:

app.api.binary_types.append('application/json')

With it, API gateway logs will show on OPTIONS call:

(6a6ea518-2ca3-436f-b74b-6e3f61c39dfb) Execution failed due to configuration error: Unable to transform request

Without it, OPTIONS works but the actual GET/PUT will fail and yield this error:

[ERROR] Runtime.MarshalError: Unable to marshal response: b'\x1f\x8b\x08\x00J\xafS^\x02\xff\xabV\xcaH\xcd\xc9\xc9W\xb2RP*\xcf/\xcaIQ\xaa\x05\x00"\xae\xa3\x86\x12\x00\x00\x00' is not JSON serializable

Damned if you do, damned if you don't.

@MartijnHarmenzon Have you been able to resolve/work around this?

Misza13 commented 4 years ago

Oh and @ricky-sb the "Test" feature works without issues. Problems arise whenever you call the API with any external tool such as Postman or fetch in the browser.

MartijnHarmenzon commented 4 years ago

@Misza13 'Glad' to hear that I am not the only one with this issue. Unfortunately, I do not have a satisfying solution. I converted my request from POST to GET and included the POST parameters within the GET url. Not the way I would like, but it works.

Misza13 commented 4 years ago

@MartijnHarmenzon I think I got to understand the issue, lead by a fix mentioned in https://forums.aws.amazon.com/message.jspa?messageID=785296#785356 - created a simple PR that fixes the OPTIONS integrations created by Chalice. I have already managed to get my API to work the way I intended based on my fork.

jamesls commented 4 years ago

Thanks for looking into this, I'll take a look at the PR shortly.