跨域问题

197 阅读4分钟

一、什么是跨域

1、同源、同源策略,同源策略限制

同源: 同源是指“协议+域名+端口号”三者相同。即便两个不同的域名指向同一个ip地址,也非同源。

同源策略是一种约定,是浏览器最核心也最基本的安全功能,如果缺少了同源策略,浏览器很容易遭受XSS、CSRF等攻击。

同源策略限制内容:

  • Cookie、LocalStorage、IndexedDB等存储性内容无法读取
  • DOM节点无法获得
  • ajax请求发送后,结果被浏览器拦截

但是有三个标签是允许跨域的:

  • <img src="XXX">
  • <link ref="XXX">
  • <script src="XXX"">

2、常见跨域场景

当协议、子域名、主域名、端口号中任意一个不相同时,都算作不同域。不同域之间相互请求资源,就算作“跨域”。常见跨域场景如下图所示:

特别注意两点:

第一、如果是协议和端口号造成的跨域,前端是无能为力的;

第二、在跨域问题上,仅仅是通过“URL的首部”来识别而不会根据域名对应的IP地址是否相同来判断。“URL的首部”可以理解为“协议, 域名和端口必须匹配”

这里你或许有个疑问:请求跨域了,那么请求到底发出去没有?

跨域并不是请求发不出去,请求能发出去,服务端能收到请求并正常返回结果,只是结果被浏览器拦截了。你可能会疑问明明通过表单的方式可以发起跨域请求,为什么 Ajax 就不会?因为归根结底,跨域是为了阻止用户读取到另一个域名下的内容,Ajax 可以获取响应,浏览器认为这不安全,所以拦截了响应。但是表单并不会获取新的内容,所以可以发起跨域请求。同时也说明了跨域并不能完全阻止 CSRF,因为请求毕竟是发出去了。

二、跨域解决方案

1、JSONP

JSONP原理:利用 <script>标签没有跨域限制的漏洞,网页可以得到从其他来源动态产生的JSON 数据。JSONP请求一定需要对方的服务器做支持才可以。

JSONP 由两部分组成:回调函数和数据。回调函数是当响应到来时应该在页面中调用的函数。回调函数的名字一般是在请求中指定的。而数据就是传入回调函数中的 JSON 数据。

动态创建<script>标签,设置其src,回调函数在src中设置:

var script = document.createElement("script");
script.src = "https://api.douban.com/v2/book/search?q=javascript&count=1&callback=handleResponse";
document.body.insertBefore(script, document.body.firstChild);

在页面中,返回的JSON作为参数传入回调函数中,我们通过回调函数来来操作数据。

function handleResponse(response){
    // 对response数据进行操作代码
    console.log(response)
}

jQuery的jsonp形式:

$.ajax({
                async : true,
                url : "https://api.douban.com/v2/book/search",
                type : "GET",
                dataType : "jsonp", // 返回的数据类型,设置为JSONP方式
                jsonp : 'callback', //指定一个查询参数名称来覆盖默认的 jsonp 回调参数名 callback
                jsonpCallback: 'handleResponse', //设置回调函数名
                data : {
                    q : "javascript", 
                    count : 1
                }, 
                success: function(response, status, xhr){
                    console.log('状态为:' + status + ',状态是:' + xhr.statusText);
                    console.log(response);
                }
    });

JSONP优缺点: JSONP优点是简单兼容性好,可用于解决主流浏览器的跨域数据访问的问题。缺点是仅支持get方法具有局限性,不安全可能会遭受XSS攻击。

2、CORS

CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)。 CORS 需要浏览器和后端同时支持。目前,所有浏览器都支持该功能,IE浏览器不能低于IE10,IE 8 和 9 需要通过 XDomainRequest 来实现。

浏览器会自动进行 CORS 通信,实现 CORS 通信的关键是后端。只要后端实现了 CORS,就实现了跨域。 服务端设置 Access-Control-Allow-Origin 就可以开启 CORS。该属性表示哪些域名可以访问资源,如果设置通配符则表示所有网站都可以访问资源。

虽然设置 CORS 和前端没什么关系,但是通过这种方式解决跨域问题的话,会在发送请求时出现两种情况,分别为简单请求复杂请求