什么是跨域?

486 阅读4分钟

如果两个页面拥有相同的协议(protocol),端口(如果指定),和主机,那么这两个页面就属于同一个源(origin),JavaScript 允许这种同源页面的数据互相通信。

JS跨域的几个层面

第一个,DOM 层面

同源策略限制了来自不同源的 JavaScript 脚本对当前 DOM 对象读和写的操作。 比如我们在www.taobao.com 这个域名下 操作www.baidu.com的DOM内容是不被允许的。

第二个,数据层面

同源策略限制了不同源的站点读取当前站点的 Cookie、IndexDB、LocalStorage 等数据。

第三个,网络层面

由于同源策略默认情况下XMLHttpRequest是默认不能访问跨域的资源。

但是为了方便web的发展我们需要出让一部分安全,引发出来的问题如XSS攻击。

为了解决XSS攻击,浏览器中引入了内容安全策略,称为 CSP。

CSP的作用

CSP 的核心思想是让服务器决定浏览器能够加载哪些资源,让服务器决定浏览器是否能够执行内联 JavaScript 代码。通过这些手段就可以大大减少 XSS 攻击

CORS跨域资源共享

端口和协议大家都应该很熟悉,默认端口(80),主机可以想像成域名或者ip。

跨域并非浏览器限制了发起跨站请求,而是跨站请求可以正常发起,但返回结果被浏览器拦截了。

有些浏览器不允许从HTTPS协议的域 跨域访问 HTTP协议,比如Chrome和Firefox,这些浏览器在请求还未发出的时候就会拦截请求,这是一个特例,值得特别关注。

假设我们直接请求百度不会出现跨域,但是当我们在百度上请求淘宝。这时候就会发生跨域,这两个域之间就会产生CORS跨域的资源共享问题。

对于端口和协议的不同,只能通过后台来解决。

主机不同如何前端解决跨域:

jsonP或者iframe

通过jsonp解决跨域

原理:HTML的script标签可以加载并执行其他域JS文件,站点B把要提供的数据作为参数传给一个站点A定义的全局函数,站点A引用这个文件就可以跨域获取数据了,A站还可以把少量参数放在script标签的src里提交给B站。 (外链JS这种方案只支持GET,受IE下url长度不能超过2083个字节的限制和出于安全考虑)

JSONP的原型:创建一个回调函数,然后在远程服务上调用这个函数并且将JSON 数据形式作为参数传递,完成回调。

将JSON数据填充进回调函数

如有localhost:8081 A页面 localhost:8082 B页面 在两个不同服务端口上。

    A页面
    <script type="text/javascript">
        //回调函数
        function callback(data) {
            alert(data.message);
        }
    </script>
    <script src="http://localhost:8082/B.js"></script>
    
    B页面
    //调用callback函数,并以json数据形式作为阐述传递,完成回调
    callback({message:"success"});

如这个接口

http://ajax.googleapis.com/ajax/services/search/web?v=1.0&q=?&callback=? 

我们需要在客户端定义回调的名字如 test1,
    
    test1(data){
        console.log('展示回调的数据',data)
    }

请求接口的时候传入参数名字
http://ajax.googleapis.com/ajax/services/search/web?v=1.0&q=?&callback=test1
这样服务端就会根据回调名字把数据返回到前端,供前端使用。

JSONP优缺点

JSONP的优点是:

  • 它不像XMLHttpRequest对象实现的Ajax请求那样受到同源策略的限制;[1]
  • 它的兼容性更好,在老版本的浏览器中可以运行,不需要XMLHttpRequest或ActiveX的支持;
  • 它在请求完毕后可以通过调用callback的方式回传结果,方便调用。

JSONP的缺点则是:

  • 它只支持GET请求而不支持POST等其它类型的HTTP请求,不能提交大量数据;
  • 它只支持跨域HTTP请求这种情况,不能解决不同域的两个页面之间如何进行JavaScript调用的问题。

跨域资源共享CROS

CORS(Cross-Origin Resource Sharing)

CORS背后的基本思想就是使用自定义的HTTP头部,让 服务器能声明 哪些来源可以通过浏览器访问该服务器上的资源,从而决定请求或响应是应该成功还是失败,CORS本身并非绝对很安全,可利用OAuth2措施来加强保障。

CORS标准强烈要求 浏览器必须先以 OPTIONS 请求方式发送一个预请求(preflight request),从而获知服务器端对跨源请求所支持 HTTP 方法。 在确认服务器允许该跨源请求的情况下,以实际的 HTTP 请求方法发送那个真正的请求。服务器端也可以通知客户端,是不是需要随同请求一起发送信用信息(包括 Cookies 和 HTTP 认证相关数据)。

如后台在filter中添加声明,即可轻松跨域

//java中的 hander() 设置,“*”号表示允许任何域向我们的服务端提交请求:
    header("Access-Control-Allow-Origin: *")

也可以通过 Nginx 反向代理机制解决前端跨域问题