Troubleshooting Cesium proxy issues with KML

Hello guys,

I'm more of a scripter (than app developer), who's worked a bit with ArcGIS and Google APIs in the past (still fairly new to recent JS / Node / Express type frameworks but working on learning them) ...meaning that I'll probably miss some concepts on the first try, but hopefully they'll sink in soon. I've only been experimenting with Cesium for a few months sporadically, and my initial goals are to transition data from some GE Enterprise and similar projects over to use a Cesium framework (like many people are trying with Cesium). We're also interested in using the Entity API some in the longer-term, but are more immediately focused on trying to integrate legacy GIS services (many are cross-origin) via your connectors like ArcGisMapServerImageryProvider, WebMapServiceImageryProvider, KmlDataSource, etc.

I'll probably post additional questions later, which related to some recent tests, but for now I'll just ask about proxies for KML (for some reason, those aren't working for me as well as for the other data types). I've been just using the recommended Node framework so far, and had some success with using the DefaultProxy object which has been included with source recently (new Cesium.DefaultProxy("/proxy/"). Recently, when I've used DefaultProxy with external ArcGIS Map Services, this setting has worked without issues (assuming no authenticated service dependencies).

For example, this source requires the proxy parameter, but works fine for me:

var agsLayer = layers.addImageryProvider(new Cesium.ArcGisMapServerImageryProvider( {
  url : "http://svinetfc3.fs.fed.us/ArcGIS_NPSG/rest/services/NPSG/Fire_Danger/MapServer",
  layers : "0",
  proxy : new Cesium.DefaultProxy("/proxy/")
}));

However, when I try the same type of thing with KmlDataSource (below - different source), it's not working for me currently:

var kmlLayer = viewer.dataSources.add(Cesium.KmlDataSource.load("http://activefiremaps.fs.fed.us/data/kml/conus.kmz"', new Cesium.DefaultProxy("/proxy/")));

The example above works fine for me with GE Client. I've also tried accessing KML files locally, but there's still CORS issues since the KML tags usually reference external sources as well. Since we're consuming multiple external services which don't (and won't) have CORS enabled, using the proxy seems our only choice in order to consume that KML data (don't have control over any external whitelists either). I've read most threads here related to KML, CORS, and proxies, but am not sure if something else changed recently with the Cesium.KmlDataSource, or if I need to do more work with proxies or Node configuration, to get external KMLs working. Why do ArcGIS Map Services work with DefaultProxy as-is, but then KML sources don't? Do these need much different handlers?

Any suggestions are appreciated.

Thanks,
Chris

CORS is definitely one of the growing pains when moving to cesium and webapps from a more desktop oriented background. It’s just one of the rules of the internet that you have to follow. Google Earth, ArcGIS, QGIS, etc. are all desktop applications and can readily ignore CORS, but the downside of webgl in the browser, especially when trying to call data from servers traditionally aligned with desktop GIS, is that you have to follow the rules of the browser.

For debugging and testing CORS issues, I recommend installing this chrome plugin:

https://chrome.google.com/webstore/detail/allow-control-allow-origi/nlfbmbojpeacfghkpbjhddihlkkiljbi?hl=en-US

which will allow you to bypass CORS temporarily so you can see if something works, and then move on to fixing/proxying the CORS issue.

Datasource loading was simplified a few releases ago, so your KML proxy example needs to use a options object, like the ArcGISImageryProvider (and all dataSources and imageryProviders, for everything but the base URL), so you just need to add some {} and proxy:

var kmlLayer = viewer.dataSources.add(Cesium.KmlDataSource.load(“http://activefiremaps.fs.fed.us/data/kml/conus.kmz”, {proxy:new Cesium.DefaultProxy("/proxy/")}));

The node configuration that comes with cesium comes with a built in proxy, but you can run cesium and the proxy on anything, as long as it’ll take the urls you need and give you back data with the CORS header attached.

There’s another approach to fixing the CORS issue though, and that is fixing it at the source. If the server that is serving out the data (ArcGIS Server on ISS, Geoserver on Apache, etc.) is configured to return CORS headers, then you don’t have a problem. A lot of public GIS servers are intended to be used by the public, but they aren’t specifically configured to tell clients connecting to them that (via the CORS header). If you know the party administering the server, it worth contacting them and seeing if they can add it. I’ve actually seen some of the larger federal GIS services start to add it to their servers of late.

Denver, thanks much for your reply, particularly the extra info about debugging (this extension will surely be handy for a lot of testing). The solution for this example was simple as you suggested, I just needed to modify the way that I was passing in the proxy object reference (which I was already doing correctly for some other sources). I tried similar edits previously, but guess I overlooked that in some recent testing - sorry that I didn't catch it first before posting.

With KML support still evolving some, there's still some cases of unsupported tags (like screen overlays), but I've been following the Cesium Roadmap and knew about some of those issues. We'll probably need to just convert data in some cases where features don't match. One project that I'm working includes an extensive collection of external sources, so we'll try to request CORS access in some cases, but will definitely need to use both strategies. Thanks again!

-Chris