I have an express server statically serving my Polymer project. I have a REST API query that I need to make, but if I make it from the client it will be blocked by CORS. So I used express-http-proxy to try to get around that; I send my request to it, and it redirects to the server that has the REST API endpoint on it. This is the entirety of my server code that's running with node server.js:
var express = require('express');
var proxy = require('express-http-proxy');
var server = express();
server.use('/', express.static(__dirname + '/'));
server.listen(8080);
server.use('/rest/api/2/search', proxy('restserver:8877'));
console.log("Server listening on localhost:8080");
When I access restserver:8877/rest/api/2/search in a browser it returns a bunch of json as a 'default' search.
On the client side, I have iron-ajax making this request:
<iron-ajax
id="getBugs"
url="/rest/api/2/search"
params=''
on-response="handleResponse"
debounce-duration="300">
</iron-ajax>
And in the script section, I'm using this.$.getBugs.generateRequest() in the ready function to send the request. So I load this up, expecting the request to not be blocked by CORS, since... it's being proxied by the server. Instead, Chrome devtools gives me this:
XMLHttpRequest cannot load http://restserver:8877/secure/MyJiraHome.jspa. Redirect from 'http://restserver:8877/secure/MyJiraHome.jspa' to 'http://restserver:8877/secure/Dashboard.jspa' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8080' is therefore not allowed access.
I don't understand why it's giving me those URLs, since I never reference them, and why it's blocking due to CORS, since it's going from the server, not the client, that being the whole point of the proxy.
It may be that express-http-proxy simply forwards the Origin header coming from your client which is http://localhost:8080, causing the end server to reject it.
Try modifying it with proxyReqOptDecorator:
server.use('/rest/api/2/search', proxy('restserver:8877', {
proxyReqOptDecorator(proxyReqOpts) {
proxyReqOpts.headers['Origin'] = 'http://accepted.origin.com';
return proxyReqOpts;
}
}));
Never used express-http-proxy and did not test it tho, so tell me if it's not a solution. Also I think using cors as other people suggested may simplify things a lot. But I don't know your development constraints, so I could be wrong.
Server is probably returning a 302 redirect which is not handled correctly in the used middleware.
Read more how the redirect works: https://en.wikipedia.org/wiki/HTTP_location
You can modify the Location response header to overcome the CORS issue or you can try:
var proxy = require('http-proxy-middleware');
var restServerProxy = proxy({target: 'http://restserver:8877', autoRewrite: true});
server.use('/rest/api/2/search', restServerProxy);
The above example should handle redirects automatically.
You don't need any proxy. Since you are calling endpoint on your server, you can just whitelist your client side for calling your server. You can do that with cors package.
https://www.npmjs.com/package/cors
First, define your CORS policy logic in one file (let's name it cors-policy-logic.js), and then export it so you can use it in other files.
const cors = require('cors');
const whitelist = ['http://localhost:8080', 'http://localhost:your_client_url'];
var corsOptionsDelegate = (req, callback) => {
var corsOptions;
if (whitelist.indexOf(req.header('Origin')) !== -1) {
corsOptions = { origin: true };
} else {
corsOptions = { origin: false };
}
callback(null, corsOptions);
};
exports.cors = cors();
exports.corsWithOptions = cors(corsOptionsDelegate);
Now, import it and use it anywhere were you define some endpoint:
var express = require('express');
const cors = require('./cors-policy-logic.js');
var server = express();
server.use('/', express.static(__dirname + '/'));
server.listen(8080);
server.route('/rest/api/2/search')
.options(cors.corsWithOptions, (req, res) => { res.sendStatus(200); })
.get(cors.cors, (req, res, next) => {
//Your business logic
});
console.log("Server listening on localhost:8080");
Alternative solution would be to use http-proxy-middleware as mentioned by #chimurai.
If you want to proxy to an https server to avoid CORS:
const proxy = require('http-proxy-middleware');
app.use('/proxy', proxy({
pathRewrite: {
'^/proxy/': '/'
},
target: 'https://server.com',
secure: false
}));
Here secure: false needs to be set to avoid UNABLE_TO_VERIFY_LEAF_SIGNATURE error.
Related
I am trying to setup a very simple nodeJS HTTP server. When I call it from the browser, like this http://localhost:8081, it works fine, but when I call is using a JS fetch() method, I get a 404 error:
GET http://localhost/:8081?q=hi
JS:
fetch(":8081/?q=hi")
NODE JS:
const requestListener = function (req, res) {
res.writeHead(200);
res.end('Hello, World!');
}
const server = http.createServer(requestListener);
server.listen(8081);
Every thing is fine, you just need to enable cors that's it, use the below code
const http = require('http')
const requestListener = function (req, res) {
const headers = {
'Access-Control-Allow-Origin': '*', /* #dev First, read about security */
'Access-Control-Allow-Methods': 'OPTIONS, POST, GET',
'Access-Control-Max-Age': 2592000, // 30 days
/** add other headers as per requirement */
};
res.writeHead(200, headers);
res.end(JSON.stringify({"key":"value"}));
}
const server = http.createServer(requestListener);
server.listen(8081);
If you are running both frontend and backend code on the same server then you don’t have to use complete url while if you are running fronted and backed on different server you need to enable cors and use complete url.
When you're calling your local server through JS fetch, you don't need to add the port number you can call it like below:
fetch('/?q=hi')
the URL handed to fetch function looks wronge, it would work if you adjust it to:
fetch('http://localhost:8081/?q=hi');
// or
fetch('/?q=hi');
it should work just fine,
and ensure that you enable the cors if you need to works from any domain
I'm having some trouble with the fetch and node.js.
In my frontend when i click a button, i would like to send a post request in order to receive an array from my backend as answer. I'n my backend i'm using node.js with express, in my frontend i'm using the fetch function.
The error that occours is the following:
Access to fetch at 'http://localhost:8080/api' from origin 'real localhost address' 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.
Code Here
const getArray = async() => {
const data = await fetch ("http://localhost:8080/api");
const dataJson = await data.json();
console.log(dataJson)
}
getArray();
In my server i've got
app.post("/api", (req,res) => {
res.sendFile(JSON.stringify(arr));
});
You need to add request options. Please refer to the MDN docs for further information.
As #Kudah said, you should read the docs.
Fetch (and XMLHttpRequest) follow the same-origin policy. This means that browsers restrict cross-origin HTTP requests from within scripts. A cross-origin request occurs when one domain (for example http://example2.com/) requests a resource from a separate domain (for example http://example1.com/).
The easiest way to solve this, (If you don't want to dig too much into this)
const whiteList = [ "https://myRealBackendUrl-1", "https://myRealBackendUrl-2" ];
// you can also pass a string here instead here instead of array
const corsOptions = {
credentials: true,
origin: process.env.NODE_ENV !== production ? "http://localhost:4000" : whiteList
// if you are in a dev environment, you probably want something like localhost
// http://localhost:4000 is just a demo backend. replace it with your own.
// if you are in a production environment, for example heroku then your backend
// url will be something like http://example.herokuapp.com
// in that case `const whiteList = [ "http://example.herokuapp.com" ];`
};
app.use(cors(corsOptions));
The above code should be enough for the normal use case.
There is also callback function, it is if you want to run some function of your own. Don't read it if you dont plan to use any dynamic checking
var corsOptionsDelegate = async (req, callback) => {
var corsOptions = { origin: false };
try {
// you can do some dynamic check here
// For example: check database for some conditions then allow access
if( myDatabaseSays == true ) corsOptions.origin = true;
else corsOptions.origin = false;
} catch (err) {
console.log(err);
// corsOptions.origin = false;
}
callback(null, corsOptions) // chain it
}
Anyway read the docs properly for more info
[1]: https://expressjs.com/en/resources/middleware/cors.html
I'd like to clone/relay the exact request to another URL in native NodeJs. For example, if you send a POST request to my site "example.com", it will send the exact same request you sent to another URL "example2.com" (data, headers etc). How could I achieve that?
You can use proxy middleware to duplicate the request. For example http-proxy-middleware will allow you to proxy the request to another server, but from what I can tell, you can only modify the response. Which isn't optimal if you don't want to wait on the proxy. You might just grab the main proxy library itself, something like:
const httpProxy = require('http-proxy');
const proxyMiddleware = httpProxy.createProxyMiddleware({
target: 'http://www.example2.com',
selfHandleResponse: true
});
const customProxyMiddleware = (req, res, next) => {
proxy.web(req, res);
next();
};
// This passes all incoming requests to the proxy but does not handle
// any of them. It simply passes it along.
app.use('/', customProxyMiddleware);
This code may not work exactly as intended but it should be a good starting point for what you are attempting.
I use Koa with Node.js 8.1.
Today I found that in my app.js, if I write in this order:
const Koa = require('koa')
var cors = require('koa-cors')
const app = new Koa()
app.use(cors(options))
app.use(router.routes())
the cors can work. I can verify the result via sending origin header in Postman, and get
Access-Control-Allow-Origin
as response header.
However, if I write in this order:
const Koa = require('koa')
var cors = require('koa-cors')
const app = new Koa()
app.use(router.routes())
app.use(cors(options))
cors will not work correctly.
What's the problem here? AM I missing something?
If you know what app.use() does, you will understand what happened.
What the use() function do is:
use(fn) {
this.middleware.push(fn);
return this;
}
So, the sequence of your code will affect the request handle process. It will route your request to your business code first and respond, cors will not be executed.
Commonly, the app.use(router.routes()) should be the last middleware.
The router routes will be modifying your request and operating on the response of it, so the cors headers need to be set prior to that, otherwise it won't work.
I have deployed (hosted) cors-anywhere in Heroku, but i don't know how to customize it.
For example, I want to add a site link in whitelist.
I get data from this link: http://fmon.asti.dost.gov.ph/dataloc.php?param=rv&dfrm=null&dto=null&numloc=1&data24=1&locs[]=711
How will I do it? I have tried touching the server.js file:
// Listen on a specific host via the HOST environment variable
var host = process.env.HOST || '0.0.0.0';
// Listen on a specific port via the PORT environment variable
//var port = process.env.PORT || 443;
var port = process.env.PORT || 8080;
// Grab the blacklist from the command-line so that we can update the blacklist without deploying
// again. CORS Anywhere is open by design, and this blacklist is not used, except for countering
// immediate abuse (e.g. denial of service). If you want to block all origins except for some,
// use originWhitelist instead.
var originBlacklist = parseEnvList(process.env.CORSANYWHERE_BLACKLIST);
//var originWhitelist = ['http://fmon.asti.dost.gov.ph/dataloc.php','https://fmon.asti.dost.gov.ph/dataloc.php','http://fmon.asti.dost.gov.ph','https://fmon.asti.dost.gov.ph'];
var originWhitelist = parseEnvList(process.env.CORSANYWHERE_WHITELIST);
function parseEnvList(env) {
if (!env) {
return [];
}
return env.split(',');
}
// Set up rate-limiting to avoid abuse of the public CORS Anywhere server.
var checkRateLimit = require('./lib/rate-limit')(process.env.CORSANYWHERE_RATELIMIT);
var cors_proxy = require('./lib/cors-anywhere');
cors_proxy.createServer({
originBlacklist: originBlacklist,
originWhitelist: originWhitelist,
requireHeader: ['origin', 'x-requested-with'],
checkRateLimit: checkRateLimit,
removeHeaders: [
'cookie',
'cookie2',
// Strip Heroku-specific headers
'x-heroku-queue-wait-time',
'x-heroku-queue-depth',
'x-heroku-dynos-in-use',
'x-request-start',
],
redirectSameOrigin: true,
httpProxyOptions: {
// Do not add X-Forwarded-For, etc. headers, because Heroku already adds it.
xfwd: false,
},
}).listen(port, host, function() {
console.log('Running CORS Anywhere on ' + host + ':' + port);
});
but when I access the data and look at the console log, it returns a 403 error which is forbidden.
NOTE: When you say self hosted CORS it will only work for your site to
proxy. CORS setting on your server is for you not for the list of
sites you mentioned. They will be having their own CORS filters setup.
403 actually refers to the forbidden resource rather than a CORS Issue. Cors issue will look something like as follows:-
No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'yourUrl' is therefore not allowed access. The response had HTTP status code 400
For cors-anywhere the whitelisting code is pretty simple as mentioned below:-
// Listen on a specific host via the HOST environment variable
var host = process.env.HOST || '0.0.0.0';
// Listen on a specific port via the PORT environment variable
var port = process.env.PORT || 8080;
var cors_proxy = require('cors-anywhere');
cors_proxy.createServer({
originWhitelist: ['http://fmon.asti.dost.gov.ph'], // Allow all origins
requireHeader: ['origin', 'x-requested-with'],
removeHeaders: ['cookie', 'cookie2']
}).listen(port, host, function() {
console.log('Running CORS Anywhere on ' + host + ':' + port);
});
This should Ideally work for you with your application calling this somewhere.
If you are getting 403 while accessing this URL from your application
then be sure the URL you mentioned is protected and you must get
proper authentication done before requesting it.
I spent 3 days looking for the cause, got a 403 error for some sites and realized that the problem may be that they can not accept requests from "origin" different from theirs.
I just tried removing those headers on the proxy server and everything worked!
removeHeaders: ['origin', 'referer']