Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

node.js and geoserver CORS

I have node.js server 0.10.12 and express.js 4.8.5. Node.js is the web server, includes openlayers 3.9.0.

Geoserver 2.1.3 serves the WMS layer. Later, I will implement vector layers.

There is only one route (for the index page)

var routes = require('./routes/index');

The index.js contains

var express = require('express');
var router = express.Router();

router.get('/', function(req, res, next) {
  res.render('index', { title: 'openlayers3 testing', head: 'Welcome' });
  next();
});

module.exports = router;

So the app.js has

var routes = require('./routes/index');//explained above

var app = express();

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');

app.use(favicon());
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded());
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

I added the following for CORS

app.use(function (req, res, next) {
    res.setHeader('Access-Control-Allow-Origin', '*');
    res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
    res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');
    res.setHeader('Access-Control-Allow-Credentials', true);
    next();
});


app.get('/', routes);

And in the index.ejs I set my Geoserver WMS layer like this

var ait = new ol.layer.Tile({
extent: textent,
source: new ol.source.TileWMS({
  url: 'http://localhost:8080/geoserver/mymap/wms',
  crossOrigin: 'anonymous',
  attributions: [new ol.Attribution({
    html: '&copy; ' +'<a href="http://www.geo.admin.ch/internet/geoportal/' +'en/home.html">' +'National parks / geo.admin.ch</a>'
  })],
   params: {'LAYERS': 'mymap:planet_osm_polygon, mymap:planet_osm_line, mymap:planet_osm_roads, mymap:planet_osm_point'},
   serverType: 'geoserver'
 })

})

And I get the error

Image from origin 'http://localhost:8080' has been blocked from loading by Cross-Origin Resource Sharing policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:5550' is therefore not allowed access.

I tried a lot of variations I found online. I put the code before the app.use(express.static(path.join(__dirname, 'public')));. I put it inside the router.get of the index.js. Still nothing. I fail to understand what is wrong.

Thanks

notes

This works in internet explorer 11. No errors and I can actually see the layer

No errors in firefox 30 but I cannot see the layer

In chrome 45 I cannot see the layer and I get that error

like image 497
slevin Avatar asked Sep 28 '15 13:09

slevin


1 Answers

Forget 'Access-Control-Allow-Origin', '*' it is a huge security risk. Set the name of the requesting domain instead and maintain a whitelist of domains.

I think it is obvious that your middleware does not set the headers in the http://localhost:8080 response. Check the headers on the network panel, firebug, etc... and debug it. How to debug the http response headers from a HTTP call

Firefox does not handle CORS errors always properly, so you should check chrome as well. Internet explorer works differently from the others: https://stackoverflow.com/a/22450633/607033 so it accepts http://localhost:5550 as same origin, that's why your buggy code works in msie. Try to use custom named domains by appending the hosts file, and I am sure you will get error message from msie as well.

edit - to catch up with the comments

The main problem with the example code, that the webapp (domain: http://localhost:5550) returns your CORS headers. Since the webapp wants to access the geoserver (http://localhost:8080) from the browser, the geoserver should grant access and not the webapp. So the geoserver should return the CORS headers instead of the webapp.

According to slevin it is not possible with the version of geoserver they currently use. A possible workaround to add a reverse proxy and serve the geoserver under a subfolder of the webapp or serve the webapp under a subfolder of the geoserver. This way they both would have the same origin. Another option to stick with different domains, but add the CORS headers to the geoserver response using the reverse proxy.

like image 188
inf3rno Avatar answered Sep 20 '22 11:09

inf3rno