针对ArcGIS Server 跨域问题的解释

XMLHttpRequest cannot load http://server/arcgis/rest/info?f=json. Origin http://localhost:8080 is not allowed by Access-Control-Allow-Origin

Leave a reply

在博客Hello World文章中提起过,以前在sinaapp中建立过wordpress博客,也写过一篇关于ArcGIS JavaScript API的文章,但是由于sinaapp开始收费以后,我的个人网站就没法访问了。今天在百度中发现尽然能搜索到此文章,而且,使用百度快照还能看见文章的内容,真是十分激动啊,于是决定趁此把文章转移到这个新博客来,呵呵。

文章内容主要是关于ArcGIS js Api v3.0版本报: XMLHttpRequest cannot loadhttp://server/arcgis/rest/info?f=json. Origin http://localhost:8080 is not allowed by Access-Control-Allow-Origin 的错误。

在esri中国社区中有同学提到:关于arcgis_js_api 3.0的问题,高手指教,在arcgis js api3.0中,在添加图层的时候浏览器开发者工具中会输出这个错误:XMLHttpRequest cannot load http://server/arcgis/rest/info?f=json. Origin http://localhost:8080 is not allowed by Access-Control-Allow-Origin,虽然对整个程序运行没有影响,但是不太美观。而且这个错误2.x的版本是没有出现的。

看见这个错误可能有点经验的同学已经大致明白是个跨域问题了。对比了一下2.8和3.0 的源码(jsapi.js文件),发现在3.0版本的esri.request方法中多了这么一段代码:esri._detectCors(req.url)(当然还有其他的代码,只是这句是解决这个问题的关键)。还有在esri.config.defaults.io中多了这两个属性:corsDetection: true, _processedCorsServers: {},还有一个属性corsEnabledServers: [],这个属性可能平时关注的同学不多,但是其实这个属性在2.5的版本中就有了,主要作用是用来存放cross-origin resource sharing enabled server 的url地址,详见Cross Origin Resource Sharing (CORS) with the ArcGIS API for JavaScript

那什么是Cross Origin Resource Sharing (CORS)呢,这个在arcgis js api中又在哪用到了呢?关于CORS,大家可以google一下,英文不好,翻译的不标准怕对你产生误导作用。我的理解是,cors是在HTML5中才有的,实现javascript跨域访问的一个协议吧。当然这一点必须得你使用的浏览器和web服务器都得支持CORS。在arcgis js api中,可能做过编辑功能的同学都知道,在做编辑的时候会使用到代理来解决跨域请求的问题,详见esri.config.defaults.io.corsEnabledServers。现在,在你的web服务器和使用的浏览器都支持CORS的情况下,遇到跨域请求的时候就不用再在你的应用程序中配置代理,只需要在esri.config.defaults.io.corsEnabledServers中添加已经配置过CORS的服务器地址就行。如:esri.config.defaults.io.corsEnabledServers.push(“servicesbeta.esri.com”);但是如果你的浏览器不支持CORS的话,还是得像以前那样设置代理页面。关于这一块可以参考:Cross-Origin Resource Sharing (CORS) – Edit Point Data

现在对CORS有一点了解了,回到代码中,我们可以看一下esri._detectCors这个函数到底做了些啥(可以打开jsapi.js.unconpressed.js查看没有压缩过的源码)。

01 esri._detectCors = function(url) {
02   // I know we don‘t want to get used to the habit of using try-catch
03   // programming, but esri.request is a core part of the API.
04   // We don‘t want unexpected(*) error in the code below to affect
05   // normal response processing workflow (not to mention what we‘re doing
06   // below is an optimization - not a critical functionality)
07   // Note: the term "unexpected" means the developer overlooked something
08  
09   var ioConfig = esri.config.defaults.io,
10       processed = ioConfig._processedCorsServers;
11   if (!ioConfig.corsDetection) {
12     return;
13   }
14   try {
15     var origin = new dojo._Url(url);
16     origin = (origin.host + (origin.port ? (":" + origin.port) :"")).toLowerCase();
17     if (
18       // Browser support
19       esri._hasCors &&
20       // ServerInfo is available since version 10.0, but token service has
21       // issues prior to 10 SP1
22       //this.version >= 10.01 &&
23       // Interested in ArcGIS REST resources only
24       (url && url.toLowerCase().indexOf("/rest/services") !== -1) &&
25       // AND server not already known to support CORS
26       (!esri._hasSameOrigin(url, window.location.href) && !esri._canDoXOXHR(url)) &&
27       // AND NOT already processed
28       !processed[origin]
29     ) {
30       //console.log("***************** esri._detectCors *********** ]", url);
31       //console.log("***************** [fetching server info] **************** ", origin);
32       processed[origin] = -1;
33       // TODO
34       // Can we use fetch "rest/services" instead of "rest/info"? This will allow
35       // 9.3 servers to get in the action.
36       // How reliable and fast is "rest/services" resource?
37  
38       // If we use esri.request, it will use proxy to get the response.
39       // We don‘t want that - because we want to find out if cross-origin
40       // XHR works. So let‘s use dojo.xhrGet directly.
41       dojo.xhrGet({
42         url: url.substring(0, url.toLowerCase().indexOf("/rest/") +"/rest/".length) + "info",
43         content: { f: "json" },
44         handleAs: "json",
45         headers: { "X-Requested-With"null }
46       }).then(
47         function(response) {
48           //console.log("REST Info response: ", arguments);
49           if (response) {
50             processed[origin] = 2;
51             // Add this server to corsEnabledServers list
52             if (!esri._canDoXOXHR(url)) {
53               ioConfig.corsEnabledServers.push(origin);
54             }
55             // Yes - response.error is also considered as confirmation for
56             // CORS support
57           }
58           else {
59             // Indicates no support for CORS on this server. Older servers
60             // that don‘t support ServerInfo will follow this path.
61             // Dojo returns null in this case.
62             processed[origin] = 1;
63           }
64         },
65         function(error) {
66           //console.error("REST Info FAILED: ", error);
67  
68           // Mark this server so that we don‘t make info request again
69           processed[origin] = 1;
70         }
71       );
72     }
73   }
74   catch (e) {
75     console.log("esri._detectCors: an unknown error occurred while detecting CORS support");
76   }
77 };

在这个函数中有这样一个请求dojo.xhrGet({…}),看见这一行代码顿时眼前一亮,这一个请求有可能就是这个错误的源, 问题应该就出在使用xhrGet来跨域请求中。那为什么代码会这样去请求呢?

我的理解这几段代码主要的意思就是:首先判断是否有需要测试浏览器和web服务器支持CORS;然后判断浏览器是否支持CORS、是否是ArcGIS REST发布的资源、暂时不清楚服务器是否支持CORS和这个服务器没有测试过这几个条件。如果满足这几个条件,就使用xhrGet去请求http://server/arcgis/rest/info?f=json来测试服务器是否支持CORS,如果支持的话就将服务器地址添加到corsEnabledServers中,并将_processedCorsServers[服务器url]值设为2,在后面的程序中使用,如果不支持的话就设为1,当然也就抛出文章介绍的这个错误。

那如何解决这个问题呢?到此也明白了这个错误的原因和出处以及CORS是什么了吧。我的理解在代码中会发出这样一个请求,应该就是为了测试我们的服务器是否支持CORS,那在我们的程序中,如果我们已经知道用户使用的浏览器不支持CORS(比如说<IE10),或者我们的服务器暂不支持CORS,或者我们铁定要继续使用代理。那我觉得我们是不是就没必要去发送这个请求来测试服务器了吧。那这样的话可以使用下面的方法来避免这个错误:

在加载地图之前,添加如下代码:

1 esri.config.defaults.io.corsDetection=false;

或者

1 esri.config.defaults.io._processedCorsServers[“你的server url”]=1;

当然,这只是我的个人见解,结合到你的实际情况可能未必正确。

关于该函数中具体的代码,你感兴趣的话可以再深入研究。这只是我的一些很浅的理解,如果你有更深的认识,欢迎批评指正。

原文地址:https://www.cnblogs.com/telwanggs/p/8819429.html

时间: 2024-10-21 21:13:21

针对ArcGIS Server 跨域问题的解释的相关文章

SQL Server跨域查询

exec sp_addlinkedserver 'linkserver','','SQLOLEDB','192.168.1.200' EXEC sp_addlinkedsrvlogin 'linkserver','false',NULL,'sa','123456' select * from linkserver.TestDB.dbo.TestTable Exec sp_droplinkedsrvlogin linkserver,Null Exec sp_dropserver linkserve

跨域:跨域及解决方法

一.什么是跨域 广义的跨域包括: 资源跳转:超链接<a>跳转.重定向.表单提交 资源嵌入:link.ifram.script.img,以及css样式中的background:url().@font-face()等外链接 脚本请求:js的ajax请求.js或DOM 中的跨域操作 狭义的跨域:指浏览器同源策略限制的请求 注意:并不是所有广义的跨域操作都不被允许,只有被同源策略限制的跨域操作是不被允许的 二.什么是浏览器同源限制 浏览器为了安全考虑不允许访问不同域下的资源 注意两点: 同源限制只是浏

前端跨域的那些事

这一节,我们来讲一讲,前端跨域的那些事,主要分成这样的几部分来讲解, 一.为什么要跨域? 二.常见的几种跨域与使用场景 2.1 JSONP跨域 2.2 iframe跨域 2.3 window.name 跨域 2.4 document.domain 跨域 2.5 cookie跨域 2.6 postMessage跨域 三.总结 一.为什么要跨域 跨域,通常情况下是说在两个不通过的域名下面无法进行正常的通信,或者说是无法获取其他域名下面的数据,这个主要的原因是,浏览器出于安全问题的考虑,采用了同源策略

AngularJS跨域请求

本文主要针对网上各种跨域请求的总结,并加入自己的验证判断,实现工作中遇到的跨域问题.所涉及到的领域很小,仅仅局限于:AngularJS CORS post 并同时需要实现json数据传送给服务器. 首先,(博文是互相转载,也没有看出原作者和原网站,我摘写其中一段:)$http.post实现跨域: 在服务器端设置允许在其他域名下访问,及响应类型.响应头设置 response.setHeader("Access-Control-Allow-Origin","*"); r

Django 跨域请求处理

参考https://blog.csdn.net/qq_27068845/article/details/73007155 http://blog.51cto.com/aaronsa/2071108 django处理Ajax跨域访问 使用javascript进行ajax访问的时候,出现如下错误 出错原因:javascript处于安全考虑,不允许跨域访问.下图是对跨域访问的解释: 概念: 这里说的js跨域是指通过js或python在不同的域之间进行数据传输或通信,比如用ajax向一个不同的域请求数据

server 2003 跨域迁移用户计算机详解

以下内容适合新手,如有大侠路过,看到文章有纰漏或者不详细的地方请私信我,我做修改后给大家提供参考,另外转载的话请注明出处,方便有疑问或者提供在迁移中遇到问题的网友来咨询,另外也欢迎大家把迁移中遇到的问题以及解决方法发给我,我会加入到文档中方便大家参考,谢谢 我介绍一下我的个人环境,我搭建了两个单林单域的服务器A和B  服务器名取名为 testA 和testB 都为Windows server 2003  A服务器域名为:contoso.com    B服务器域名为:contosob.com B服

ArcGIS API for Silverlight 调用WebService出现跨域访问报错的解决方法

原文:ArcGIS API for Silverlight 调用WebService出现跨域访问报错的解决方法 群里好几个朋友都提到过这样的问题,说他们在Silverlight中调用了WebService方法,总报这个错误,贴图如下: 解决办法: 1.确定你的Silverlight项目及承载Silverlight的Web程序根目录下都包含2个跨域文件,分别是crossdomain.xml和clientaccesspolicy.xml: crossdomain.xml文件,如下: <?xml ve

第五节:SignalR大杂烩(与MVC融合、全局的几个配置、跨域的应用、C/S程序充当Client和Server)

一. 说在前面的话 本节主要在前面章节的基础上补充了几个简单的知识点,比如:第三方调用通过 GlobalHost.ConnectionManager.GetHubContext<MySpecHub1>();来获取Hub对象,那么能不能封装一下不必每次都这么获取呢?再比如SignalR传输是否有大小限制,一下传输10w个字能否传输成功?最后着重整理一下跨域的各种使用情况,结合C/S程序充当客户端和服务器端. 本节内容包括: ①. SignalR与MVC或者WebApi简单的整合. ②. 全局的几

跨域解释

同源策略 在说跨域之前,首先需要了解的一个概念就是”同源策略“. 什么是源? 源=协议+域名+端口号. 如果两个url的协议.域名.端口号完全一致,那么这两个url就是同源的. 我们可以通过window.origin或location.origin得到当前源. https://wang.comhttps://ergou.com//不同源,域名不一致(记住:只有完全一模一样才算同源)http://wang.com/index.htmlhttp://wang.com/server.php//同源lo