Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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!

like image 969
Encoder Avatar asked Feb 09 '17 15:02

Encoder


People also ask

How do I fix not allowed by Access-Control allow origin?

There Are Two Approaches to Getting It Right.Use a reverse proxy server or WSGI server(such as Nginx or Apache) to proxy requests to your resource and handle the OPTIONS method in the proxy. Add support for handling the OPTIONS method in the resource's code.

How do I turn on all Access-Control allow origin?

Limiting the possible Access-Control-Allow-Origin values to a set of allowed origins requires code on the server side to check the value of the Origin request header, compare that to a list of allowed origins, and then if the Origin value is in the list, set the Access-Control-Allow-Origin value to the same value as ...

How does Access-Control allow origin work?

Access-Control-Allow-Origin is a CORS (cross-origin resource sharing) header. When Site A tries to fetch content from Site B, Site B can send an Access-Control-Allow-Origin response header to tell the browser that the content of this page is accessible to certain origins.


2 Answers

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.

like image 66
ryanmac Avatar answered Sep 23 '22 00:09

ryanmac


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();
});
like image 21
noob Avatar answered Sep 25 '22 00:09

noob