什么是跨域访问,如何实现跨域?
什么是跨域请求?
在 HTML 中,<a>
, <form>
, <img>
, <script>
, <iframe>
, <link>
等标签以及 Ajax 都可以指向一个资源地址,而所谓的跨域请求就是指:当前发起请求的域与该请求指向的资源所在的域不一样。这里的域指的是这样的一个概念:我们认为若协议 + 域名 + 端口号均相同,那么就是同域。
同源策略(Same-origin Policy)
同源策略是一种约定,它是浏览器最核心也最基本的安全功能。以下特征被称之为同源
同源策略有两种限制,第一种是限制了不同源之间的请求交互,例如在使用XMLHttpRequest 或 fetch 函数时则会受到同源策略的约束。 第二个限制是浏览器中不同源的框架之间是不能进行js的交互操作的。比如通过iframe和window.open产生的不同源的窗口。这两种限制都有不同的解决方案,下面会讲解不同的解决方案和可能产生的安全问题。
同协议 如:https://exp.org 与 http://exp.org 不同源
同端口 如:http://exp.org 与 http://exp.org:8080 不同源
同域名 如:http://aaa.org 与 http://bbb.org 不同源
同源策略有两种限制,第一种是限制了不同源之间的请求交互,例如在使用XMLHttpRequest 或 fetch 函数时则会受到同源策略的约束。 第二个限制是浏览器中不同源的框架之间是不能进行js的交互操作的。比如通过iframe和window.open产生的不同源的窗口。这两种限制都有不同的解决方案,下面会讲解不同的解决方案和可能产生的安全问题。
跨域请求有什么隐患?
通常浏览器会对跨域请求作出限制。浏览器之所以要对跨域请求作出限制,是出于安全方面的考虑,因为跨域请求有可能被不法分子利用来发动 CSRF攻击( 跨站请求攻击 )。
跨站请求攻击,简单地说,是攻击者通过一些技术手段欺骗用户的浏览器去访问一个自己曾经认证过的网站并运行一些操作(如发邮件,发消息,甚至财产操作如转账和购买商品)。由于浏览器曾经认证过,所以被访问的网站会认为是真正的用户操作而去运行。这利用了web中用户身份验证的一个漏洞:简单的身份验证只能保证请求发自某个用户的浏览器,却不能保证请求本身是用户自愿发出的。
JSONP实现跨域
原理:
JSONP 是一种非官方的跨域数据交互协议
SONP 的理念就是,与服务端约定好一个回调函数名,服务端接收到请求后,将返回一段 Javascript,在这段 Javascript 代码中调用了约定好的回调函数,并且将数据作为参数进行传递。当网页接收到这段 Javascript 代码后,就会执行这个回调函数,这时数据已经成功传输到客户端了。
JSONP 本质上是利用
<script><img><iframe>
等标签不受同源策略限制,可以从不同域加载并执行资源的特性,来实现数据跨域传输。JSONP由两部分组成:回调函数和数据。回调函数是当响应到来时应该在页面中调用的函数,而数据就是传入回调函数中的JSON数据。
示例:
// Using YQL and JSONP $.ajax({ url: "http://query.yahooapis.com/v1/public/yql", // The name of the callback parameter, as specified by the YQL service jsonp: "callback", // Tell jQuery we're expecting JSONP dataType: "jsonp", // Tell YQL what we want and that we want JSON data: { q: "select title,abstract,url from search.news where query=\"cat\"", format: "json" }, // Work with the response success: function( response ) { console.log( response ); // server response } });
优缺点:
JSONP 的优点是:它不像XMLHttpRequest
对象实现的Ajax请求那样受到同源策略的限制;它的兼容性更好,在更加古老的浏览器中都可以运行。
JSONP 的缺点是:它只支持 GET 请求,而不支持 POST 请求等其他类型的 HTTP 请求
CORS实现跨域
在跨域请求中使用了非默认的 Methods
、Content-Type
、Headers
浏览器会首先发起一个OPTIONS
方法的请求,来验证是否通过。
允许跨域请求的方法
浏览器默认允许跨域请求的方法只有 GET
HEAD
POST
,需要添加更多方法则需要在服务端添加 Access-Control-Allow-Methods
。
'Access-Control-Allow-Methods':'DELETE, PUT ' //允许所有站点跨域请求,也可以设置成某一个具体站点
允许跨域请求的Content-Type
浏览器默认允许跨域请求的Content-Type
只有 text/plain
multipart/form-data
application/x-www-form-urlencoded
自定义请求头
如果在请求方法中添加了自定义请求头,如果服务端没有对相应的头进行 Access-Control-Allow-Heards
的设置,则客户端会报跨域的错误
'Access-Control-Allow-Heards':'X-Test-Cors' //X-Test-Cors 为自定义的请求头
Access-Control-Max-Age
允许预请求的时间。
'Access-Control-Max-Age':'1000'
在1000s内经过预请求的Methods
、Content-Type
、Headers
不需要再重新预请求验证