ArcGIS API for Javascript 二次開發跨域報錯

ArcGIS API for Javascript 二次開發。服務器用的tomcat。在調用服務的時候,由於一個服務是在另一臺服務器上,讀取服務的時候出現了跨域報錯。這裏寫圖片描述

百度,兩種方式:一個是程序前面添加Responese.Header.Add(“Accee-Crotrol-Allow-Origin”,”*”),這個我不知道在程序哪裏添加,即使添加了也報錯;一個實服務器端找到crossdomain.xml文件,修改,我的這個文件裏,原本就有這句話,只是後面有個securte”false”。服務器不怎麼設置。所以想別的方法。

搜到這個文章:http://www.gis520.com/thread-1799-1-1.html
這個是從Esri的角度來寫解決方案。copy如下
“XMLHttpRequest cannot load http://server/arcgis/rest/info?f=json. Origin http://localhost:8080 is not allowed by Access-Control-Allow-Origin錯誤解決方法:

文章內容主要是關於ArcGIS js Api v3.0版本報: XMLHttpRequest cannot load http://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(比如說

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章