什么是同源策略
同源策略/SOP(Same origin policy)是一种约定,由 Netscape 公司 1995 年引入浏览器,它是浏览器最核心也最基本的安全功能,现在所有支持 JavaScript 的浏览器都会使用这个策略。
同源策略可防止 JavaScript 发起跨域请求。源被定义为协议(protocol)、域名(port)、端口(host)的组合,三个要素缺一不可。
看下面的比较一目了然:
不同源的客户端脚本在没有明确授权的情况下是不允许读写其他网站的资源
同源策略的限制:
Cookie、LocalStorage 和 IndexDB 会话存储无法读取
DOM无法获得
AJAX请求不能发送
同源策略的作用:
防止恶意网站可以回去其他网站的时候,获取数据
防止恶意网站 ifame其他网站的时候,获取数据
防止恶意网站在自己网站有访问其他网站的权利,一面通过 cookie 免登,拿到数据
总的来说同源策略的作用就是限制来自另一个域的资源交互,从而保障我们网站的隐私和数据的安全。
安全性和可用性:
浏览器在安全性和可用性之间做了取舍。对于小项目来说,我们把所有的资源都放在自有服务器上面。对于中大型项目来说,由于服务器价格比较贵,我们项目的静态资源文件,像图片、视频等,需要托管在第三方来消减运营成本,所以浏览器在遵循安全性的基础上,放宽了限制,允许img、script、style标签进行跨域引用资源
那么我们还有其他的方式来解决跨域吗,我们接着往下看
怎样去解决跨域问题
跨域产生的原因:
这这里就不过多赘述了,在上面已经提到了,总体的说就是:一个域名想去访问另一个域名下的资源,但是因为同源策略不同的原因,产生了跨域。所以浏览器阻止了访问
那么我的请求是否发出去了?
跨域并不是请求发不出去,请求时可以发出去的,服务端能收到请求也能正常返回结果,只是结果被浏览器拦截了
跨域的解决方案:
1、Jsonp
1)JSONP原理
利用 <script> 标签没有跨域限制的漏洞,网页可以得到从其他来源动态产生的 JSON 数据。JSONP请求一定需要对方的服务器做支持才可以
2)JSONP和AJAX对比
JSONP和AJAX相同,都是客户端向服务器端发送请求,从服务器端获取数据的方式。但AJAX属于同源策略,JSONP属于非同源策略(跨域请求)
3)JSONP的优缺点
JSONP优点是简单兼容性好,可用于解决主流浏览器的跨域数据访问的问题。缺点是仅支持get方法具有局限性,不安全可能会遭受XSS攻击。
在开发中可能会遇到多个 JSONP 请求的回调函数名是相同的,这时候就需要自己封装一个 JSONP函数
上面这段代码相当于向http://localhost:3000/say?wd=hello&callback=show这个地址请求数据,然后后台返回show('hello test'),最后会运行show()这个函数,打印出'hello test'
jQuery的jsonp形式
2、Cors
CORS 需要浏览器和后端同时支持。IE 8 和 9需要通过 XDomainRequest 来实现。
浏览器会自动进行 CORS 通信,实现 CORS 通信的关键是后端。只要后端实现了 CORS,就实现了跨域。
服务端设置 Access-Control-Allow-Origin 就可以开启 CORS。 该属性表示哪些域名可以访问资源,如果设置通配符则表示所有网站都可以访问资源。
虽然设置 CORS 和前端没什么关系,但是通过这种方式解决跨域问题的话,会在发送请求时出现两种情况,分别为简单请求和复杂请求
1)简单请求
只要同时满足两个条件就属于简单请求
条件1:使下面方法其中一个
· GET
· HEAD
· POST
条件2:Content-Type 的值仅限于下面三个之一
· text/plain
· multipart/form-data
· application/x-www-form-urlencoded
2)复杂请求
不符合以上条件的请求就肯定是复杂请求了。
复杂请求的CORS请求,会在正式通信之前,增加一次HTTP查询请求,称为"预检"请求,该请求是 option 方法的,通过该请求来知道服务端是否允许跨域请求
我们用PUT向后台请求时,属于复杂请求,后台需做如下配置
接下来我们看下一个完整复杂请求的例子,并且介绍下CORS请求相关的字段
上述代码由http://localhost:3000/index.html向http://localhost:4000/跨域请求,正如我们上面所说的,后端是实现 CORS 通信的关键
3.Node中间件代理
实现原理:同源策略是浏览器需要遵循的标准,而如果是服务器向服务器请求就无需遵循同源策略。代理服务器,需要做以下几个步骤:
· 接受客户端请求 。
· 将请求 转发给服务器。
· 拿到服务器 响应 数据。
· 将响应转发给客户端。
举个例子:本地文件index.html文件,通过代理服务器http://localhost:3000向目标服务器http://localhost:4000请求数据。
上述代码经过两次跨域,值得注意的是浏览器向代理服务器发送请求,也遵循同源策略,最后在index.html文件打印出{"title":"你好","password":"111111"}
4.nginx反向代理
实现原理类似于Node中间件代理,需要你搭建一个中转nginx服务器,用于转发请求。 使用nginx反向代理实现跨域,是最简单的跨域方式。只需要修改nginx的配置即可解决跨域问题,支持所有浏览器,支持session,不需要修改任何代码,并且不会影响服务器性能
实现思路:通过nginx配置一个代理服务器(域名与domain1相同,端口不同)做跳板机,反向代理访问domain2接口,并且可以顺便修改cookie中domain信息,方便当前域cookie写入,实现跨域登录。
先下载nginx,然后将nginx目录下的nginx.conf修改如下:
总结:
CORS支持所有类型的HTTP请求,是跨域HTTP请求的根本解决方案
JSONP只支持GET请求,JSONP的优势在于支持老式浏览器,以及可以向不支持CORS的网站请求数据。
不管是Node中间件代理还是nginx反向代理,主要是通过同源策略对服务器不加限制。
日常工作中,用得比较多的跨域方案是cors和nginx反向代理