3

I'm trying to add a publicly-accessible WMS layer to an ArcGIS Server JavaScript API v4 map, and am encountering a CORS error.

See the simple demo which loads the ArcGIS JS API WMS layer:

// ArcGIS WMS layer fails
const layer = new WMSLayer({
  url: "https://environment.data.gov.uk/spatialdata/historic-landfill/wms",
  sublayers: [{name: "Historic_Landfill_Sites"}]
});

This returns a CORS error:

Access to fetch at 'https://environment.data.gov.uk/spatialdata/historic-landfill/wms?SERVICE=WMS&REQUEST=GetCapabilities' from origin 'https://fiddle.jshell.net' 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.

(The demo is hosted on JSFiddle but the same behaviour occurs on my laptop during development, with the error message being for origin http://localhost, or if I host the HTML page elsewhere online).

Note that this same layer works when added to a Leaflet map (demo), on the same machine, using the identical URL:

// Leaflet WMS layer works
var wmsLayer2 = L.tileLayer.wms('https://environment.data.gov.uk/spatialdata/historic-landfill/wms', {
  layers: 'Historic_Landfill_Sites',
  transparent: true,
  format: 'image/png'
});

How is Leaflet able to circumvent the CORS error, and can I use this approach to get the WMS layer to work in ArcGIS Server?

1
  • 3
    If you read ESRI docs about WMSLayer API, you can see the following: The WMSLayer is used to create layers based on OGC Web Map Services (WMS). The WMSLayer initially executes a WMS GetCapabilities request, which might require CORS or a proxy page. This call to GetCapabilities (which causes CORS error) is the main difference with Leaflet API, where no such call is made.
    – TomazicM
    Commented Mar 3, 2022 at 9:00

1 Answer 1

3

Let me quote https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#what_requests_use_cors :

This cross-origin sharing standard can enable cross-origin HTTP requests for:

  • Invocations of the XMLHttpRequest or Fetch APIs, as discussed above.
  • Web Fonts (for cross-domain font usage in @font-face within CSS), so that servers can deploy TrueType fonts that can only be loaded cross-origin and used by web sites that are permitted to do so.
  • WebGL textures.
  • Images/video frames drawn to a canvas using drawImage().
  • CSS Shapes from images.

Of that list, three are of interest for your question:

  • Loading the GetCapabilities document via fetch()
  • Loading map tiles in a <canvas>
    • Via 2D canvas' drawImage()
    • Via WebGL

While not explicitly stated, loading images via a HTMLImageElement, i.e. via a <img> HTML tag, is not subject to CORS.

Leaflet uses the latter method - one <img> per tile, and does not request the GetCapabilities document.

This is not without drawbacks - notably, the nefarious "one pixel gap between tiles" bug, plus needing to specify all WMS parameters (instead of getting that information from the GetCapabilities document).

I don't know how the arcgis JS API works, but given your error message, it's safe to say it does request the GetCapabilities document via fetch().

Do note that Leaflet plugins that perform canvas manipulation on tiles (e.g. TileLayer.NoGap, TileLayer.GL, TileLayer.Colorizr, etc), or that perform either GetCapabilities or GetFeatureInfo requests, are subject to CORS restrictions.

can I use this approach to get the WMS layer to work in ArcGIS Server?

Not without rewriting half of the code for the arcgis JS API (which is even not really an option since it would imply reverse engineering the code therefore angering esri's lawyers).

As an interim solution, you might want to consider setting up a mapproxy instance. The default value for its Access-control-allow-origin setting is permissive.

4
  • See my comment to the question about cause of the CORS error.
    – TomazicM
    Commented Mar 3, 2022 at 9:02
  • @TomazicM Yeah, I addressed that in an edit. Commented Mar 3, 2022 at 9:09
  • many thanks to both of you, I appreciate the thorough answer. I'll give the proxy approach a test - I'm also trying the Esri resource proxy approach, but this is causing its own cross-origin issues in my React app as the proxy uses a different port to the application. There's another question here if you fancy diving further into the CORS rabbit hole with me ;) Commented Mar 3, 2022 at 22:36
  • Thanks for the vote of confidence, but I swore to myself to never again touch any react code even with a 10-foot pole. Commented Mar 3, 2022 at 22:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.