针对ArcGIS Server 跨域问题的解释
在博客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 跨域问题的解释的更多相关文章
- swoole,http\server 跨域---记一次php网站跨域访问上机实验
缘由:为了更好的体验swoole组件优良的协程Mysql客户端,实现更好的并发设计:写了一个小程序. 环境准备: 没有采用任何框架,只是使用了smarty模版,来渲染后端php响应的数据,在一个htm ...
- SQL Server 跨域访问
# SQL Server 跨服务器访问数据 参考链接: [sp_addlinkedserver](https://msdn.microsoft.com/zh-cn/library/ms190479.a ...
- jQuery.getJSON跨域访问的正确使用方式(史上最傻瓜式解释)
最近花了2天时间完整的看了一遍 jQuery 的API,其中 $.getJSON(url[, data][, callback]) 方法的跨域访问解释真心看的一头雾水,大家可以从这里感受一下: htt ...
- Javascript跨域后台设置拦截
子域名之间互相访问需要跨域 结论放在开头: 服务端必须设置允许跨域 客户端带cookie需要设置withCredentials 无论服务端是否允许跨域,该request都会完整执行 options预请 ...
- ASP.NET MVC & WebApi 中实现Cors来让Ajax可以跨域访问 (转载)
什么是Cors? CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing).它允许浏览器向跨源服务器,发出XMLHttpReq ...
- NGINX: 配置跨域请求
说明: 内容全部来自 SegmentFault Developer Nginx 配置跨域请求 跨域请求失败, nginx 报错: 403 No 'Access-Control-Allow-Origin ...
- .NET MVC & Web API Cors让AJAX 实现跨域
什么是Cors? CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing).它允许浏览器向跨源服务器,发出XMLHttpReq ...
- Nginx解决跨域问题(CORS)
跨域 解决跨域问题一般有两种思路: CORS 在后端服务器设置 HTTP 响应头,把你需要运行访问的域名加入加入 Access-Control-Allow-Origin中. jsonp 把后端根据请求 ...
- django处理跨域
django处理Ajax跨域访问时使用javascript进行ajax访问的时候,出现如下错误 出错原因:javascript处于安全考虑,不允许跨域访问.下图是对跨域访问的解释: 概念: 这里说的j ...
随机推荐
- Spring Service、Dao进行Junit单元测试
pring对Controller.Service.Dao进行Junit单元测试总结 所有用Junit进行单元测试,都需要下面的配置 @RunWith(SpringJUnit4ClassRunner ...
- Laravel 使用Voyager导致多个数据库连接总是返回默认连接?
问题与分析 最近的项目碰到一个奇怪的问题,在Laravel(5.3)中想建立多个数据库连接连到MySQL的不同数据库(另一个连接名为conn2),执行如下语句得到却发现得到的仍然是默认连接: $con ...
- Magento 2开发教程 - 如何添加新产品属性
添加产品属性是一种在Magento 1 和 Magento 2最受欢迎的业务. 属性是解决许多与产品相关的实际任务的有力方法. 这是一个相当广泛的话题,但在这个视频中,我们将讨论添加一个下拉类型属性到 ...
- windows 下配置ndk环境,无需cygwin
时隔好久要用ndk编译jni库,本以为配制安装cygwin环境,便按部就班的下载安装,但是公司的网速真的不给力,三天安装了三四次都没有安装成功(我选择的是在线安装),于是我便开始查ndk的官网看看,发 ...
- iframe适应屏幕大小,隐藏滚动条,移动端
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat=&qu ...
- SZU4
#include <iostream> #include <string> #include <cstring> #include <cstdlib> ...
- 小任务之Canvas绘制时钟
背景图的绘制(大圆.数字.小圆点) 掌握基础知识:圆的绘制(arc方法),关于圆的弧度的计算,数学中关于sin cos的用法 圆的弧度为2*Math.PI 12个数字分得弧度每个为2*Math.PI/ ...
- JS里的居民们6-数组排序
编码 var arr = [43, 54, 4, -4, 84, 100, 58, 27, 140]; 将上面数组分别按从大到小以及从小到大进行排序后在console中输出 var arr = ['a ...
- Strapi 安装易错位置
Strapi官网(https://strapi.io)介绍:最先进的开源内容管理框架,可以毫不费力地构建功能强大的API,建立在Node.js平台之上,为您的API提供高速惊人的表现. 简单点说,(对 ...
- Flex和MyEclipse10整合时候需要注意的问题
1.myeclipse和flex的位数要一致,不能混着安装 2.独立安装完Adobe Flash Builder 4.6 Installer之后,在其的安装文件夹下有一个utilities文件夹下有一 ...