Encoder
Encoder

Reputation: 535

Access-Control-Allow-Origin not working Google Cloud Functions GCF

I feel like a newbie here but I'm trying to run a simple AJAX request from a browser to access a GCF and Chrome is reporting:

XMLHttpRequest cannot load https://us-central1-bustling-opus-830.cloudfunctions.net/Authenticate. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'https://beast.reachboarding.com.au' is therefore not allowed access.

I've got a function called Authenticate (as shown above) that's using a bucket called:

bustling-opus-830.appspot.com

I've used gsutil to set CORS using the following JSON file:

[{
    "origin": ["https://beast.localdev.com.au","*"],
    "responseHeader": ["Content-Type"],
    "method": ["GET", "HEAD", "DELETE", "OPTIONS"],
    "maxAgeSeconds": 3600
}]

With the following command:

gsutil cors set cors.json gs://bustling-opus-830.appspot.com/

And then get the following output from the corresponding get command:

gsutil cors get gs://bustling-opus-830.appspot.com/

[{"maxAgeSeconds": 3600, "method": ["GET", "HEAD", "DELETE", "OPTIONS"], "origin": ["https://beast.localdev.com.au", "*"], "responseHeader": ["Content-Type"]}]

I'm using the default example code that's provided when you create a new function as stated below:

/**
 * Responds to any HTTP request that can provide a "message" field in the body.
 *
 * @param {!Object} req Cloud Function request context.
 * @param {!Object} res Cloud Function response context.
 */
exports.helloWorld = function helloWorld(req, res) {
    // Example input: {"message": "Hello!"}
    if (req.body.message === undefined) {
        // This is an error case, as "message" is required.
        res.status(200).send('No message defined!');
    } else {
        // Everything is okay.
        console.log(req.body.message);
        res.status(200).send(req.body.message);
    }
};

And a simple HTML with the following Javascript:

$.ajax({
    url: "https://us-central1-bustling-opus-830.cloudfunctions.net/Authenticate",
    type: "POST",
    data: {
        message: 'Testing'
    },
    dataType: 'json', 
    success: function (response) {
        console.log(response);
    },
    error: function (xhr, status) {
        console.log(xhr);
    }
});

Which is causing the error.

In my DEV console I can see the network request go through. Here are the HTTP Response Headers I'm getting are:

cache-control:private
content-encoding:gzip
content-length:27
content-type:text/html; charset=utf-8
date:Wed, 08 Feb 2017 03:45:50 GMT
etag:W/"7-274e639a"
function-execution-id:azc1zqfb1tq8
server:Google Frontend
status:200
vary:Accept-Encoding
x-cloud-trace-context:70e08d634a9644c32530326de0471a64;o=1
x-cloud-trace-context:70e08d634a9644c32530326de0471a64
x-powered-by:Express

I would have expected to see the Access-Control-Allow-Origin header within the Response Headers to indicate that it was allowing * but I'm definitely not seeing it.

The crazy thing though is that when I look at the Network item and click on Response I get:

Testing

Which suggests that all things being equal, it ACTUALLY ran!

I apologise if this has been answered before but I've searched for as many different keywords and nothing seems to have solved my problem. I thought a fresh pair of eyes on the issue (and some decent expertise) would help.

Thanks in advance!

Upvotes: 19

Views: 17754

Answers (3)

0xC0DED00D
0xC0DED00D

Reputation: 20368

You can also use the cors package to fix this, as recommended by Google. In fact, they also use this in their own sample codes. Check this example. This is the code -

const cors = require('cors')({
    origin: true,
});

//Your code here

//Use the following function instead of just res.send. return keyword is not compulsory here
return cors(req, res, () => {
    res.send();
});

Upvotes: 9

mhaligowski
mhaligowski

Reputation: 2222

If you are still interested in an answer, I actually wrote a blog post on how to handle that with Express middleware: https://mhaligowski.github.io/blog/2017/03/10/cors-in-cloud-functions.html.

Upvotes: 0

ryanmac
ryanmac

Reputation: 441

Your foreground (HTTP) Google Cloud Function needs to set the appropriate CORS headers in the responses to the AJAX client requests. The request and response parameters of HTTP Functions have equivalent properties to the corresponding ExpressJS objects which can be used to set the CORS headers and respond to preflight requests as needed.

For example:

exports.Authenticate = function Authenticate (req, res) {
    //set JSON content type and CORS headers for the response
    res.header('Content-Type','application/json');
    res.header('Access-Control-Allow-Origin', '*');
    res.header('Access-Control-Allow-Headers', 'Content-Type');

    //respond to CORS preflight requests
    if (req.method == 'OPTIONS') {
        res.status(204).send('');
    }

    //continue function ...

};

The headers and logic above should be modified to reflect the particular needs of your service but should hopefully help you get started.

Upvotes: 35

Related Questions