在博客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;

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

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

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

  1. swoole,http\server 跨域---记一次php网站跨域访问上机实验

    缘由:为了更好的体验swoole组件优良的协程Mysql客户端,实现更好的并发设计:写了一个小程序. 环境准备: 没有采用任何框架,只是使用了smarty模版,来渲染后端php响应的数据,在一个htm ...

  2. SQL Server 跨域访问

    # SQL Server 跨服务器访问数据 参考链接: [sp_addlinkedserver](https://msdn.microsoft.com/zh-cn/library/ms190479.a ...

  3. jQuery.getJSON跨域访问的正确使用方式(史上最傻瓜式解释)

    最近花了2天时间完整的看了一遍 jQuery 的API,其中 $.getJSON(url[, data][, callback]) 方法的跨域访问解释真心看的一头雾水,大家可以从这里感受一下: htt ...

  4. Javascript跨域后台设置拦截

    子域名之间互相访问需要跨域 结论放在开头: 服务端必须设置允许跨域 客户端带cookie需要设置withCredentials 无论服务端是否允许跨域,该request都会完整执行 options预请 ...

  5. ASP.NET MVC & WebApi 中实现Cors来让Ajax可以跨域访问 (转载)

    什么是Cors? CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing).它允许浏览器向跨源服务器,发出XMLHttpReq ...

  6. NGINX: 配置跨域请求

    说明: 内容全部来自 SegmentFault Developer Nginx 配置跨域请求 跨域请求失败, nginx 报错: 403 No 'Access-Control-Allow-Origin ...

  7. .NET MVC & Web API Cors让AJAX 实现跨域

    什么是Cors? CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing).它允许浏览器向跨源服务器,发出XMLHttpReq ...

  8. Nginx解决跨域问题(CORS)

    跨域 解决跨域问题一般有两种思路: CORS 在后端服务器设置 HTTP 响应头,把你需要运行访问的域名加入加入 Access-Control-Allow-Origin中. jsonp 把后端根据请求 ...

  9. django处理跨域

    django处理Ajax跨域访问时使用javascript进行ajax访问的时候,出现如下错误 出错原因:javascript处于安全考虑,不允许跨域访问.下图是对跨域访问的解释: 概念: 这里说的j ...

随机推荐

  1. 我Java学习时的模样(三)

    读Java源码 平常使用Java的时候,那些集合类使用起来很顺手,但是有没有想过这些集合内部的实现原理是怎样的,它的添加移除都有哪些操作? 有了一些工作经验之后,必须要读一读Java包中的源码,需要知 ...

  2. input输入时软键盘回车显示搜索

    很多时候我们会看到输入法里面回车是搜索等字眼,今天我们就来实现这个效果 原本的效果: <form action=""> <input type="sea ...

  3. SQLite.dll在xp中部署时的报错处理

    错误信息: System.IO.FileNotFoundException: Could not load file or assembly 'System.Data.SQLite.dll' or o ...

  4. 二:SpringAOP

    一:AOP 面向切面编程思想 横向重复,纵向抽取 |- filter中 |- 动态代理 |- interceptor中 二:动态代理 1.通过动态代理可以体现aop思想 2.对目标对象中的方法进行增强 ...

  5. The Struts dispatcher cannot be found. This is usually caused by using Struts tags without the associated filter.

    The Struts dispatcher cannot be found. This is usually caused by using Struts tags without the assoc ...

  6. jmeter单一接口测试

    在使用jmeter进行单一接口测试之前,我们先来了解一下一个用户请求的过程,如下: 1)用户通过浏览器发起一个请求: 2)用户收到服务器返回的响应数据. 如上,就是一个WEB的请求/响应模型 jmet ...

  7. 《MySQL 基础课程》笔记整理(进阶篇)(未完)

    一.MySQL服务安装及命令使用 安装过程就不写了,毕竟百度经验一大把 MySQL 官方文档 MySQL 参考手册中文版 1.MySQL简介 ​ RDBMS(Relational Database M ...

  8. Apache2.4+PHP7.3 安装及整合教程[Windows]

    系统环境:Win10 64位 Apache版本:2.4.37 64位 PHP版本:7.3.1 64位 下载 安装的第一步肯定是下载了,可以直接到我的网盘(密码:18tp)下载,下载完成后将文件解压到你 ...

  9. 来看看javaweb的自定义标签

    1.为什么需要自定义标签? jsp的简单标签其实就是jsp的自定义标签,主要作用就是移除jsp页面中的java代码,使得jsp页面只有标签和EL表达式,而没有java代码.利用自定义标签,可以使软件开 ...

  10. js控制input text字符键入/字符长度限制/字母自动大写

    功能: 1.仅允许指定字符键入 2.限制长度 实现代码: <input type="text" style="width: 6em" name=" ...