參考文章:http://www.cnblogs.com/dowinning/archive/2012/04/19/json-jsonp-jquery.htmljavascript
JavaScript出於安全方面的考慮,不容許跨域調用其餘頁面的對象。但在安全限制的同時也給注入iframe或是ajax應用上帶來了很多麻煩。這裏把涉及到跨域的一些問題簡單地整理一下:html
首先什麼是跨域,簡單地理解就是由於JavaScript同源策略的限制,a.com 域名下的js沒法操做b.com或是c.a.com域名下的對象。更詳細的說明能夠看下錶:前端
URL | 說明 | 是否容許通訊 |
---|---|---|
http://www.a.com/a.js http://www.a.com/b.js |
同一域名下 | 容許 |
http://www.a.com/lab/a.js http://www.a.com/script/b.js |
同一域名下不一樣文件夾 | 容許 |
http://www.a.com:8000/a.js http://www.a.com/b.js |
同一域名,不一樣端口 | 不容許 |
http://www.a.com/a.js https://www.a.com/b.js |
同一域名,不一樣協議 | 不容許 |
http://www.a.com/a.js http://70.32.92.74/b.js |
域名和域名對應ip | 不容許 |
http://www.a.com/a.js http://script.a.com/b.js |
主域相同,子域不一樣 | 不容許 |
http://www.a.com/a.js http://a.com/b.js |
同一域名,不一樣二級域名(同上) | 不容許(cookie這種狀況下也不容許訪問) |
http://www.cnblogs.com/a.js http://www.a.com/b.js |
不一樣域名 | 不容許 |
接下來簡單地總結一下在「前臺」通常處理跨域的辦法,後臺proxy這種方案牽涉到後臺配置,這裏就不闡述了,有興趣的能夠看看yahoo的這篇文章:《JavaScript: Use a Web Proxy for Cross-Domain XMLHttpRequest Calls》java
1、WebApi:jquery
// 爲測試JSONP跨域而寫 [HttpGet] public void GetAll(string callback) { List<User> retList = new List<User>(); Context context = new Context(); var users = context.Users.ToList(); if (users != null && users.Count > 0) { retList = users; } context.Dispose(); //return "callback(" + JsonConvert.SerializeObject(retList) + ")"; HttpContext.Current.Response.Write(callback + "(" + JsonConvert.SerializeObject(retList) + ")"); HttpContext.Current.Response.End(); }
以項目A中的一個WebApi方法做爲實驗中的接口,接口地址http://localhost:616/api/UserService/GetAll,訪問方式爲GETajax
2、測試頁面:json
<html> <head> <title>test</title> <script src="~/Scripts/jquery-1.7.1.min.js"></script> <script type="text/javascript"> function callAPI() { $.ajax({ type: "GET", url: "http://localhost:616/api/UserService/GetAll", dataType: "application/json;charset=utf-8", success: function (result) { alert(result); }, error: function (e) { var test = e; } }); } function callAPIByJSONP() { var test = 1; $.ajax({ type: "GET", async: false, url: "http://localhost:616/api/UserService/GetAll", dataType: "jsonp", jsonp: "callback", jsonpCallback:"handler", success: function (result) { alert(result[0].UserName); }, error: function (e) { var test = e; } }); } </script> </head> <body> <input type="button" value="普通調用" onclick="callAPI();" /> <input type="button" value="JSONP調用" onclick="callAPIByJSONP();" /> </body> </html>
測試頁面只包括兩個按鈕,一個是普通的ajax調用WebApi接口,另外一個是用JSONP調用WebApi接口。api
當使用通常的Ajax調用時會提示下面信息:跨域
No Access-Control-Allow-Orgin,此時不能經過ajax獲取其餘服務器上的數據。安全
3、使用JSONP跨域:
JSONP的大體原理是前臺請求跨域服務器上的腳本時是不會受跨域的影響的,好比:<script type=text/javascript src='www.abc.com' />。所以只須要跨域服務根據前端的需求動態生成js,這個js包括了執行的方法以及數據,這樣就實現了相似於ajax的效果。不過JSONP和ajax有着本質的區別:ajax的核心是經過XmlHttpRequest獲取非本頁面的內容,而JSONP的核心是動態添加<script>標籤來調用服務器動態生成的js腳本。
function callAPIByJSONP() { var test = 1; $.ajax({ type: "GET", async: false, url: "http://localhost:616/api/UserService/GetAll", dataType: "jsonp", jsonp: "callback", jsonpCallback:"handler", success: function (result) { alert(result[0].UserName); }, error: function (e) { var test = e; } }); }
注意點:
剛開始後臺方法返回值爲string類型,返回值爲:return callback(回調方法名)+(數據),這樣返回的Code爲200,statusText爲success,可是不會進入到success回調函數裏,而是進入error中。
後來在網上查找緣由,不少回答都是說返回的數據格式有問題,可是按照他們提供的格式和上面我寫的是同樣的。最後修改後臺方法,使用HttpContext.Current.Response.Write的方式返回數據,問題解決。
// 爲測試JSONP跨域而寫 [HttpGet] public void GetAll(string callback) { List<User> retList = new List<User>(); Context context = new Context(); var users = context.Users.ToList(); if (users != null && users.Count > 0) { retList = users; } context.Dispose(); //return "callback(" + JsonConvert.SerializeObject(retList) + ")"; HttpContext.Current.Response.Write(callback + "(" + JsonConvert.SerializeObject(retList) + ")"); HttpContext.Current.Response.End(); }
前臺獲取的數據:
另外,因爲JSONP的原理是動態添加<script>,所以JSONP的請求方式是GET,即便指定了type:"POST"最後JSONP向後臺服務請求的方式仍是GET得方式