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 Answer 1
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 viafetch()
- Loading map tiles in a
<canvas>
- Via 2D canvas'
drawImage()
- Via WebGL
- Via 2D canvas'
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.
-
See my comment to the question about cause of the CORS error.TomazicM– TomazicM2022年03月03日 09:02:24 +00:00Commented Mar 3, 2022 at 9:02
-
@TomazicM Yeah, I addressed that in an edit.IvanSanchez– IvanSanchez2022年03月03日 09:09:14 +00:00Commented 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 ;)Stephen Lead– Stephen Lead2022年03月03日 22:36:26 +00:00Commented 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.IvanSanchez– IvanSanchez2022年03月03日 22:39:42 +00:00Commented Mar 3, 2022 at 22:39
Explore related questions
See similar questions with these tags.
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 toGetCapabilities
(which causes CORS error) is the main difference with Leaflet API, where no such call is made.