同源策略与跨域
跨域请求解决方案
同源策略与跨域
首先,我们看一个例子(以 ASP.NET MVC 为例 )
在index视图页中,使用Jquery AJAX方式请求Controller Action方法。(同源请求,一切正常)
在本地新建一个 html文件,使用Jquery AJAX方式请求 位于 IIS EXPRESS 上的方法。(浏览器拦截跨域请求)
在例子中,涉及到了一个重要的概念——同源策略(Same-Origin Policy)。所谓的 同源 是指域名、协议、端口号 相同。不同的客户端脚本(javascript,ActionScript)在没有授权的情况下,不能读取对方资源。简单来说,浏览器允许包含在页面A的脚本访问第二个页面B的数据资源,这一切是建立在A和B页面是同源的基础上。
同源策略
同源策略 是由Netscape提出的一个著名的安全策略,现在所有支持JavaScript 的浏览器都会使用这个策略。实际上,这种策略只是一个规范,并不是强制要求,各大厂商的浏览器只是针对同源策略的一种实现。它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。
跨域与跨域请求
跨域 简单的来说,指的是两个资源非同源。出于安全方面的考虑,页面中的JavaScript在请求非同源的资源时就会出 跨域问题 ——即跨域请求,这时,由于同源策略,我们的请求会被浏览器禁止。也就出现了 我们常说的 跨域 问题。
下面,我们看一下,具体哪些情况会出现跨域问题(具体策略限制):
主流跨域请求解决方案
JSONP 实现跨域
为了便于客户端使用数据,逐渐形成了一种非正式传输协议。人们把它称作JSONP。该协议的一个要点就是允许用户传递一个callback参数给服务端,然后服务端返回数据时会将这个callback参数作为函数名来包裹住JSON数据,这样客户端就可以随意定制自己的函数来自动处理返回数据了。
jsonp的核心是动态添加 script标签 来调用服务器提供的js脚本。
备注:详细的解释,可以看一下这篇文章,超级详细。说说JSON和JSONP
JSONP实现原理?
1、JS 跨域请求资源会被限制。但是在页面中,script 标签跨域时,却是没有限制的(frame,img同理)。
2、我们通过,script的src属性,请求服务器,并通过参数(如:?callback=foo,foo为本地一个执行的方法)告诉服务器返回指定格式的JS脚本,并将数据封装在此脚本中。
3、服务器再配合客户端返回一段脚本 (如:* foo({“id”: 123, “name” : 张三, “age”: 17});* ),其实返回的就是 一个客户端本地的一个 可执行的方法的方法名, 并将要返回的 数据封装在了参数 里。
4、请求到资源后,本地就会执行此方法,通过对参数的处理,也就获取到了我们所要的数据。
具体实现
- 客户端
p><input id="btn3" type="button" name="name" value="AJAXGET2_Param" onclick="AJAXRequest('/Test/AnotherFunc', 'GET', { 'request': 'wys' }, 'jsonp')"/></p>
<script>
var ServerUrl = 'http://localhost:33268';
//TODO: 封装 公用方法
//AJAX 请求
function AJAXRequest(url, type, data, dataType) {
$.ajax({
url: ServerUrl+url,
type: type,
data: data,
dataType: dataType,
jsonpCallback: foo,
success: function (data) {
console.log(data.staus);
},
error: function (err) {
alert('错误信息:' + err);
}
});
}
</script>
2.服务器
public string AnotherFunc(string request)
{
string str = "foo({\"staus\":\"world\"})";
return str;
}
3.运行结果
4.注意事项
服务器返回数据的格式
是返回的JSONP格式,而不是单纯的JSON。返回的是一段JS脚本(客户端的一个可执行的方法,参数为JSON 格式的数据,是要返回的数据)。如果单纯的返回JSON数据,虽然客户端也能看数据,但是却会报错,不能执行请求成功的回调函数。报错原因,可以看下这里。其实就是我上面解释的,JSONP 的根本原理所要求的,要以这样的格式。
JSONP的局限性
JSONP 方式,固然方便强大。但是他的局限性在于,它无法完成POST请求。即是我们将type改为post,在发送请求时,依然会是以Get的方式。- 注意JSON数据格式
服务器端需要将字符串拼接转义,键名 需要使用双引号
- 注意JSON数据格式
string str = "foo({\"staus\":\"world\"})";
CORS跨域
CORS原理
CORS(Cross-Origin-Resource Sharing,跨院资源共享)是一种允许多种资源(图片,Css文字,Javascript等)在一个Web页面请求域之外的另一个域的资源的机制。 跨域资源共享这种机制让Web应用服务器支持跨站访问控制,从而使得安全的进行跨站数据传输成为了可能。
具体方案
通过这种机制设置一系列的响应头,这些响应头允许浏览器与服务器进行交流,实现资源共享。
看一下具体Demo,同样是 最初的示例代码,这次我们不使用JSONP的跨域的方式,我们配置一下IIS 服务器(修改WebConfig文件),增添一下响应头。PS: 其他修改响应头方式,请见已上连接。
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
</customHeaders>
</httpProtocol>
</system.webServer>
</configuration>
我们可以看一下运行结果:
* CORS 解决方案相对于JSONP 更加灵活,而且支持POST请求,是跨域的根源性解决方案。
引用补充:
刚刚说到的兼容性。CORS是W3C中一项较新的方案,所以部分浏览器还没有对其进行支持或者完美支持,详情可移至 http://www.w3.org/TR/cors/
安全问题。CORS提供了一种跨域请求方案,但没有为安全访问提供足够的保障机制,如果你需要信息的绝对安全,不要依赖CORS当中的权限制度,应当使用更多其它的措施来保障,比如OAuth2。
代理层
JSONP 和CORS 是主流的 跨域问题 的解决方案。除了他们呐,还有一种解决方案,就是代理层。简要说一下。
JS 调用本源的后台的方法(这样就不存在跨域的问题),而通过后台(任何具有网络访问功能的后台语言,ASP.NET ,JAVA,PHP等)去跨域请求资源,而后将结果返回至前台。
参考资料:
https://www.w3.org/TR/cors/
http://kb.cnblogs.com/page/139725/
http://www.freebuf.com/articles/web/65468.html
http://www.jb51.net/article/42629.htm
http://www.nowamagic.net/librarys/veda/detail/224/
http://www.open-open.com/lib/view/open1344558130468.html