HTTP POST Firebase Cloud Function "Access-Control-Allow-Origin" error - node.js

I try to make HTTP POST request but I get this error
(everything is ok when I use same function on my angularjs project using __$http__) I searched similar questions here but I think I am missing a basic point on my JS request code.
Access to XMLHttpRequest at 'https://us-central1-MYAPP.cloudfunctions.net/app/MYURL' from origin has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
Firebase side:
const functions = require('firebase-functions');
const express = require('express');
const cors = require('cors');
const app = express();
app.use(cors({ origin: true }));
app.post('/MYURL', (req, res) => {
// my function goes here
var clientKey = req.body.clientKey;
return res.status(200).send(clientKey);
});
exports.app = functions.https.onRequest(app);
My request code:
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function () {
if (this.readyState == 4 && this.status == 200) {
console.log(this.responseText);
}
};
xhttp.open("POST", "https://us-central1-MYAPP.cloudfunctions.net/app/MYURL", true);
xhttp.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
xhttp.setRequestHeader("Access-Control-Allow-Origin", "*");
xhttp.send("clientKey=XXXXX");

Since it has been a couple of days after my question, I want to share the result here. I contacted to Firebase Support and got replied that everything should be ok with my code. I know it is funny but it works without any CORS error right now. The fact is that I really did not change anything.

Related

No 'Access-Control-Allow-Origin' header is present on the requested resource in Express app

I have an Express app running on same server with my Web app. I'm trying to make a XMLHttpRequest to my Express app and I get this error:
Access to XMLHttpRequest at 'http://10.0.0.222:9999/' from origin 'http://10.0.0.222:8080' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
Though in my app this header is clearly 'present'.
App code:
var cors = require('cors')
const util = require('util');
var inspect = require('eyes').inspector({maxLength: false})
const express = require('express');
var bodyParser = require('body-parser')
const app = express();
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
var corsOptions = {
origin: 'http://10.0.0.222:8080',
optionsSuccessStatus: 200, // some legacy browsers (IE11, various SmartTVs) choke on 204
}
app.post('/', cors(corsOptions), function (req, res) {
console.dir(req.body, {depth: null});
res.send('a');
});
const PORT = process.env.PORT || 9999;
app.listen(PORT, () => {
console.log(`Server listening on port ${PORT}...`);
});
XMLHttpRequest Code:
var xhr = new XMLHttpRequest();
xhr.open("POST", 'http://10.0.0.222:9999', true);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(goodJSON)
Why do I still get this error even though the origin option has my web app's host included?
It won't work because you have placed the headers in the base route i.e /.
You must check the headers before resolving the route. In your case route is already resolved and then you are applying the cors headers.
Use this:
app.use('/', cors(corsOptions)); or app.use(cors(corsOptions));
app.post('/', function (req, res) {
console.dir(req.body, {depth: null});
res.send('a');
});
Applying cors in app.use will add the headers. After that path will be resolved and it won't throw the error
The error message says:
Response to preflight request
The preflight is an OPTIONS request sent to ask permission to make the actual request.
Your handler only accepts POST requests, so the OPTIONS request doesn't have the required headers on it.
The documentation specifically covers preflight requests:
app.options('/', cors(corsOptions));

Node Express Cors issue

I cant figure why the cors express middleware wont work. cors, express, and ejs are all saved in package.json. The app works fine if I add corsanywhere proxy on the front end but id like to work around this on the server side. any help much appreciated I've been stuck on this.
the api is in the get View/index path
the error is:
Access to fetch at 'https://api.darksky.net/forecast/' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
const express = require('express');
const app = express();
const ejs = require('ejs');
const cors = require('cors');
const PORT = process.env.PORT || 3000;
// app.use((req, res, next) => {
// res.header('Access-Control-Allow-Origin', '*')
// res.header('Access-Control-Allow-Headers', 'Origin', 'X-Requested-With')
// next();
// });
app.use(cors());
app.use(express.static(__dirname + '/Public'));
app.set('view engine', 'ejs');
app.get('/', cors(), (req, res) => {
res.render(__dirname + '/Views/index')
});
app.listen(PORT, () => {
console.log(`server is listening on ${PORT}`)
});
client side:
it works with the ${proxy} in there but id like to get rid of that
if(navigator.geolocation){
navigator.geolocation.getCurrentPosition(position => {
long = position.coords.longitude;
lat = position.coords.latitude;
var proxy = 'https://cors-anywhere.herokuapp.com/'
var api = `${proxy}https://api.darksky.net/forecast/042750f3abefefdfe2c9d43cf33ce576/${lat},${long}`;
fetch(api)
.then(response => {
return response.json();
})
.then(data => {
let {temperature, summary, icon,} = data.currently;
temperatureDegree.textContent = Math.floor(temperature);
temperatureDescription.textContent = summary;
locationTimezone.textContent = data.timezone;
setIcons(icon, document.querySelector('.icon'
w
``````
So, if you're trying to access some other service https://api.darksky.net/forecast/ (that you don't control) from your web page, then there is nothing you can do to make CORs work for that. It's up to the api.darksky.net server to decide if CORs is allowed or not. You can't change that.
You could make a request from your web page to your server to ask it to get some data from api.darksky.net for you and then return it back to your webpage (working as a simple proxy). Your server is not subject to any CORs limitations when accessing api.darksky.net. Only browsers are limited by CORs.
And, as you've found, you can also use a proxy service that enables CORs and fetches data for you.
Let's suppose you want to proxy the parts of the darksky API, you could do something simple like this:
const express = require('express');
const app = express();
const request = require('request');
const apiRouter = express.Router();
// maps /api/forecast/whatever to http://api.darksky.net/forecast/developerKey/whatever
// and pipes the response back
const apiKey = "yourAPIKeyHere";
apiRouter.get("/*", (req, res, next) => {
// parse out action and params
// from an incoming URL of /api/forecast/42.3601,-71.0589
// the /api will be the root of the router (so not in the URL here)
// "forecast" will be the action
// "42.3601,-71.0589" will be the params
let parts = req.path.slice(1).split("/"); // split into path segments, skipping leading /
let action = parts[0]; // take first path segment as the action
let params = parts.slice(1).join("/"); // take everything else for params
request({
uri: `https://api.darksky.net/${action}/${apiKey}/${params}`,
method: "get"
}).pipe(res);
});
app.use("/api", apiRouter);
app.listen(80);
Now, when you send this server, this request:
/api/forecast/42.3601,-71.0589
it will request:
https://api.darksky.net/forecast/yourAPIKeyHere/42.3601,-71.0589
and pipe the result back to the caller. I ran this test app and it worked for me. While I didn't see anything other than forecast URLs in the darksky.net API, it would work for anything of the format /api/someAction/someParams.
Note, you probably do NOT want to enable CORS on your server because you don't want other people's web pages to be able to use your proxy. And, since you're just sending requests to your own server now, you don't need CORS to be able to do that.

Firefox CORS failure with express node server

I'm using Express.js with the CORS middleware. I'm getting very strange behavior on Firefox v73.0.1 (64-bit)
Clean firefox profile... so nothing is cached.
I try a direct request to http://localhost/search?q=AMZN, I get results as expected.
I open my webapp which is running on localhost:3000. All of these requests are not using TLS/SSL.
I get "Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost/search?q=AMZN. (Reason: CORS request did not succeed)." when it tries to reach out to the API server backend.
I refresh the other tab where I was accessing localhost directly (same request which succeeded before), and I get a "connection reset".
Chrome does not do this...
I have been looking at wireshark and Firefox simply sends a GET request (several of them? Why?? I'm only making one), sends the headers and such, then it is followed by connection reset.
Sounds like node is doing something wrong? Or I dunno.
const express = require('express');
const fetch = require('node-fetch');
const util = require('util');
const app = express();
const port = 80;
var cors = require('cors')
var copts = {
origin: function (origin, callback) {
console.log('yeah');
// allow all
callback(null, true);
}
}
const SEARCH_URL = 'https://api.stocktwits.com/api/2/streams/symbol/%s.json';
app.get('/search', cors(copts), (req, res) => {
The "yeah" part never is hit at all.
Very simple clientside code.
return fetch(BACKEND_URL + uri).then(response => {
Tried removing CORS middleware and added these headers, based on examining github's cross-browser request-response in chrome
res.header('Access-Control-Allow-Methods', 'GET');
res.header('Access-Control-Max-Age', '3600');
res.header('Vary', 'Origin, Access-Control-Request-Headers, Access-Control-Request-Method, Accept-Encoding');
res.header('Access-Control-Allow-Origin', '*');
I didn't really have the options handler captured so maybe this didnt matter. I found those headers in the GET response.
It might be possible that the node server get crashed on an invalid reqeust and hence you are getting the reset error.
With cors package:
You need to add optionsSuccessStatus property in the cors options for some legacy browsers. And OPTIONS handler To enable pre-flightin requests.
const express = require('express');
const fetch = require('node-fetch');
const util = require('util');
const app = express();
const port = 80;
var cors = require('cors')
var copts = {
origin: function (origin, callback) {
console.log('yeah');
callback(null, true);
},
optionsSuccessStatus: 200
}
app.options("*", cors(copts));
const SEARCH_URL = 'https://api.stocktwits.com/api/2/streams/symbol/%s.json';
app.get('/search', cors(copts), (req, res) => { });
With headers.:
You are missing Access-Control-Allow-Headers in the response headers, you need to add the Access-Control-Allow-Headers header in the response header to allow the Access-Control-Allow-Origin header.
Try this.
const express = require('express');
const fetch = require('node-fetch');
const util = require('util');
const app = express();
const port = 80;
var cors = require('cors')
var copts = {
origin: function (origin, callback) {
console.log('yeah');
// allow all
callback(null, true);
}
}
const SEARCH_URL = 'https://api.stocktwits.com/api/2/streams/symbol/%s.json';
app.get('/search', (req, res) => {
res.header('Access-Control-Allow-Methods', 'GET, OPTIONS');
res.header('Access-Control-Allow-Headers', 'Origin');
res.header('Access-Control-Allow-Origin', '*');
res.status(200).send("Ok")
});
in my case, FireFox removes the request header from ajax to a http url, but works fine with https
Have you updated your front end package.json file with the following?
"proxy": "http://localhost:[your port here]/",
try assigning CORS to the express server like so:
const cors = require('cors');
app.use(cors());

response is empty when trying send a request GET with vanilla JS to express

I want to create a request GET that returns a json data type with ajax
The route is so simply like this:
app.get('/', function(req, res) {
res.json({ answer: 42})
});
When I open / in the browser it render this:
All ok, but I trying to get answer json with XMLHttpRequest vanilla JS (no jquery):
var xhr = new XMLHttpRequest();
xhr.open("GET", 'http://localhost:3000/');
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.responseType = 'json'
xhr.addEventListener('load', function () {
alert(this.response) // response is 'null'
})
xhr.send();
the response property is null and thw browser look like this:
I get nothing back. What am I missing here?
I don't see any issue with the code It must be a cross domain issue. The reason it works from postman is it handle the preflight automatically. You need to enable cors in your express server like this.
const express = require('express')
const app = express();
var cors = require('cors')
app.use(cors())
app.get('/', function(req, res) {
res.json({ answer: 42})
});
app.listen(3000, () => {
console.log("listening");
});
Hope it helps.

Google Firebase Functions - Timeout when doing HTTP requests

So I am trying to make a simple proxy (I think that's the right word) and I've come up with some code that works fine locally. I can call 'firebase serve --only functions' and the function works fine and I get expected results. Now when I deploy this same code, and try calling it it just times out. I have no idea why, so I was hoping I could get some help.
Here's the code:
//Variables
const functions = require('firebase-functions');
const express = require('express');
const cors = require('cors');
const request = require('request');
//App
const app = express();
app.use(cors({ origin: true }));
//Endpoints
app.get('/**', function(req, res) {
request('https://example.com' + req.url, function(err, proxyRes, body) {
//Err
if (err) {
res.send('Error: ' + err.code);
return
}
//Res
res.status(200).send(body);
});
});
//Functions
exports.proxy = functions.https.onRequest(app);
HTTP functions will time out if they don’t send a response. This means your request() is probably failing, and it’s probably failing because, on the free Spark payment plan, you can’t make outgoing requests to services that Google doesn’t fully control.
Your function should send a response in all conditions in order to avoid a timeout. This means you should be checking for errors all the time.

Resources