4
votes

Ive followed instructions at https://cloud.google.com/functions/docs/writing/http#functions_http_cors-python

So my code has this at the end

 # Set CORS headers for the preflight request
        if request.method == 'OPTIONS':
            # Allows GET requests from any origin with the Content-Type
            # header and caches preflight response for an 3600s
            headers = {
                'Access-Control-Allow-Origin': '*',
                'Access-Control-Allow-Methods': 'GET',
                'Access-Control-Allow-Headers': 'Content-Type',
                'Access-Control-Max-Age': '3600'
            }

            return ('', 204, headers)

        # Set CORS headers for the main request
        headers = {
            'Content-Type':'application/json',
            'Access-Control-Allow-Origin': '*',
            'Access-Control-Allow-Headers': 'Content-Type',
        }

        # END CORS

        return (res, 200, headers)

where res is JSON

from a simple node app, im calling via

this.http.post(payloadTarget.url, JSON.stringify(clone)).subscribe(res => {
    console.log('request complete', res);
  },
  err => {
    console.log('request failed', err);
  });

im getting this error on console

No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:4200' is therefore not allowed access.

when testing a POST or OPTIONS using Postman i dont see the error but i also dont see the HEADERS im supposed to

im sure its something simple but looking at others similar questions and answers cant find anything that points to my issue

3
I've just tried to reproduce this and it works for me, are you sure you've deployed the latest version of your function? What do you get when you send an OPTIONS request with curl? curl -i -X OPTIONS <your function URL> - Dustin Ingram
Hi @Dustin, I deploy using gcloud functions deploy functionName --runtime python37 --trigger-http and the curl returns HTTP/2 200 content-type: text/html; charset=utf-8 function-execution-id: ms2z3dcwv1tz x-cloud-trace-context: d4b120a314d0d4a2bb8b7f57d0f5baa7;o=1 date: Thu, 01 Nov 2018 07:47:38 GMT server: Google Frontend content-length: 2 alt-svc: quic=":443"; ma=2592000; v="44,43,39,35" - Tariq
I'm also getting the same issue. Tried with curl -i -X OPTIONS <your function URL> and I get access-control-allow-headers: Content-Type access-control-allow-methods: POST, OPTIONS access-control-allow-origin: * access-control-max-age: 3600 content-type: text/html; charset=utf-8 Just doesn't work with Chrome. - Watson

3 Answers

4
votes

I think the issue here is that you've left out the POST from your OPTIONS response. With CORS you'll need to be specific about which http methods are acceptable. With that being said, you'll need to update your pre-flight request to:

    # Set CORS headers for the preflight request
    if request.method == 'OPTIONS':
        # Allows GET requests from any origin with the Content-Type
        # header and caches preflight response for an 3600s
        headers = {
            'Access-Control-Allow-Origin': '*',
            'Access-Control-Allow-Methods': 'GET, POST',
            'Access-Control-Allow-Headers': 'Content-Type',
            'Access-Control-Max-Age': '3600'
        }

        return ('', 204, headers)

    # Set CORS headers for the main request
    headers = {
        'Content-Type':'application/json',
        'Access-Control-Allow-Origin': '*',
        'Access-Control-Allow-Headers': 'Content-Type',
    }

    # END CORS

    return (res, 200, headers)

Alternatively, you can set the value to:

'Access-Control-Allow-Methods': '*'

If you aren't that concerned with security.

Also, the reason you're not getting these errors via POSTMAN is due to the nature of the request - All modern browsers intercept your request and check to see if the origins match (domain, port, protocol, etc), if they don't, a pre-flight (OPTIONS) request is made to the the destination to make sure that its okay. Sites like POSTMAN and software like Fiddler aren't initiated from the browser and are submitted without any checks.

1
votes

You could create a function that adds CORS to each response. Use jsonify to cast a dict into JSON.

from flask import jsonify

def addCors(response, code=200):
    headers = {'Access-Control-Allow-Origin': '*'}
    return (response, code, headers)

def func_with_cors(request):
    response = jsonify({"key1":"value1","key2":"value2"})
    return addCors(response)

then deploy func_with_cors

gcloud functions deploy func_with_cors --runtime python37 --trigger-http

0
votes

This happens when I put an annotation to the function. I added this annotation because Cloud Functions doesn't show detailed error logs for Python. My function returns expected headers when I removed the annotation.