参考文章: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得方式