最近ajax訪問webservice遇到跨域的問題,網上搜尋資料,總結如下(很多都是覺得人家總結不錯的複製下來)
>
先上我的已實作程式碼:
前端程式碼:
$.ajax({ type: "get", url: "http://localhost/service1.asmx/getelevatorstatusjsondata?jsoncallback=?", datatype: "jsonp", jsonp: "json", data: "", success: function (result) { var data = eval(result); for (var i = 0; i < data.length; i++) { alert(data[i].id + "--" + data[i].name); } }, error: function (a, b, c) { alert(c); } });
服務端程式碼:
/// <summary> /// 获取状态数据信息 /// </summary> /// <returns></returns> [webmethod] public void getelevatorstatusjsondata() { list<list<deviceinfo>> elevatordatas = new list<list<deviceinfo>>(); list<senddicdate> searchlist = xmlserializehelper.xmldeserializefromfile<list<senddicdate>>(@configutil.servicepath + configutil.getconfigbykey("xmlpath") + "查询指令信息.xml", encoding.utf8); foreach (senddicdate item in searchlist) { string key = item.portno + "-" + item.bordrate + "-" + item.sendtype; list<deviceinfo> deviceinfolist = (list<deviceinfo>)context.cache.get(key); elevatordatas.add(deviceinfolist); } string result = ""; datacontractjsonserializer json = new datacontractjsonserializer(elevatordatas.gettype()); using (memorystream stream = new memorystream()) { json.writeobject(stream, elevatordatas); result = encoding.utf8.getstring(stream.toarray()); } string jsoncallback = httpcontext.current.request["jsoncallback"]; result = jsoncallback + '(' + result + ')'; httpcontext.current.response.write(result); httpcontext.current.response.end(); }
c#
以上是呼叫c#服務端的實作程式碼,下面的是java端的,參數可能有差異,但原理是相通的
java:
string callbackfunname = context.request["callbackparam"]; context.response.write(callbackfunname + "([ { \"name\":\"john\"}])");
ps:客戶端的jsonp參數是用來透過url傳參,傳遞jsonpcallback參數的參數名,比較拗口,通俗點講:
jsonp: ""
jsonpcallback:""
順帶一提:在chrome瀏覽器裡,也可以在服務端設定header訊息context.response.addheader("access-control-allow-origin", "*");來達到跨網域要求的目的,且不需要設定ajax以下參數
datatype : "jsonp", jsonp: "callbackparam", jsonpcallback:"jsonpcallback1"
以正常ajax請求方式就可以取得資料。
下面是原理,看別人講解的,感覺很有道理:
1、一個眾所周知的問題,ajax直接請求普通文件存在跨域無權限訪問的問題,甭管你是靜態頁面、動態網頁、web服務、wcf,只要是跨域請求,一律不准;
2、不過我們又發現,web頁面上調用js檔案時則不受是否跨域的影響(不僅如此,我們還發現凡是擁有」src」這個屬性的標籤都擁有跨域的能力,例如
3、於是可以判斷,當前階段如果想透過純web端(activex控制項、服務端代理、屬於未來的html5之websocket等方式不算)跨網域存取資料就只有一種可能,那就是在遠端伺服器上設法把資料裝進js格式的檔案裡,供客戶端呼叫和進一步處理;
4、恰巧我們已經知道有一種叫做json的純字符數據格式可以簡潔的描述複雜數據,更妙的是json還被js原生支持,所以在客戶端幾乎可以隨心所欲的處理這種格式的數據;
5、這樣子解決方案就呼之欲出了,web客戶端透過與調用腳本一模一樣的方式,來調用跨域伺服器上動態生成的js格式檔案(一般以json為後綴),顯而易見,伺服器之所以要動態產生json文件,目的就在於把客戶端需要的資料裝進去。
6、客戶端在對json檔案呼叫成功之後,也就獲得了自己所需的數據,剩下的就是按照自己需求進行處理和展現了,這種獲取遠端數據的方式看起來非常像ajax ,但其實不一樣。
7、為了方便客戶端使用數據,逐漸形成了一種非正式傳輸協議,人們把它稱作jsonp,該協議的一個要點就是允許用戶傳遞一個callback 參數給服務端,然後服務端返回數據時會將這個callback參數當作函數名稱來包裹住json數據,這樣客戶端就可以隨意自訂自己的函數來自動處理回傳資料了。
聰明的開發者很容易想到,只要服務端提供的js腳本是動態生成的就行了嗔,這樣呼叫者可以傳一個參數過去告訴服務端「我想要一段呼叫xxx函數的js程式碼,請你回傳給我”,於是伺服器就可以按照客戶端的需求來產生js腳本並回應了。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><title></title><script type="text/javascript">// 得到航班信息查询结果后的回调函数var flightHandler =function(data){ alert('你查询的航班结果是:piao价 '+ data.price +' 元,'+'余piao '+ data.tickets +' 张。'); }; // 提供jsonp服务的url地址(不管是什么类型的地址,最终生成的返回值都是一段javascript代码)var url ="http://flightQuery.com/jsonp/flightResult.aspx?code=CA1998&callback=flightHandler"; // 创建script标签,设置其属性var script = document.createElement('script'); script.setAttribute('src', url); // 把script标签加入head,此时调用开始 //document.getElementsByTagName('head')[0].appendChild(script); </script></head><body></body></html> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><title>Untitled Page</title><script type="text/javascript" src=jquery.min.js"></script><script type="text/javascript"> jQuery(document).ready(function(){ $.ajax({ type: "get", async: false, url: "http://flightQuery.com/jsonp/flightResult.aspx?code=CA1998", dataType: "jsonp", jsonp: "callback",//传递给请求处理程序或页面的,用以获得jsonp回调函数名的参数名(一般默认为:callback) jsonpCallback:"flightHandler",//自定义的jsonp回调函数名称,默认为jQuery自动生成的随机函数名,也可以写"?",jQuery会自动为你处理数据 success: function(json){ alert('您查询到航班信息:piao价: '+ json.price +' 元,余piao: '+ json.tickets +' 张。'); }, error: function(){ alert('fail'); } }); }); </script></head><body></body></html>
是不是有點奇怪?為什麼我這次沒有寫flighthandler這個函式呢?而且竟然也運作成功了!哈哈,這就是jquery的功勞了,jquery在處理jsonp類型的ajax時(還是忍不住吐槽,雖然jquery也把jsonp歸入了ajax,但其實它們真的不是一回事),自動幫你生成回調函數並把資料取出來供success屬性方法來調用,是不是很爽呀?