同源策略
同源策略,它是由Netscape提出的一个驰名的安全策略。当初所有反对JavaScript 的浏览器都会应用这个策略来对脚本和申请进行校验,若不同源,则禁止应用。

同源的定义
那如果判断是否同源?次要依据三个维度,域名,协定,端口三个都雷同才算同源。
举个 :

网站A网站B后果
http://www.zhenai.comhttp://i...不同源,域名不同http://www.zhenai.comhttp://w...不同源,域名不同http://www.zhenai.comhttps://...不同源,协定不同http://www.zhenai.comhttp://w...不同源,端口不同(默认端口80)

同源策略的作用
①无奈用js读取非同源的Cookie、LocalStorage 和 IndexDB
这个次要是为了避免歹意网站通过js获取用户其余网站的cookie等用户信息。

②无奈用js获取非同源的DOM
避免歹意网站通过iframe获取页面dom,从而窃取页面的信息。

③无奈用js发送非同源的AJAX申请
避免歹意的申请攻打服务器窃取数据信息。

那是不是说非同源的申请就无奈实现呢?也不是,这就引出了咱们本文次要论述的解决跨域申请问题的办法。

jsonp
jsonp能实现跨域是利用了img、script和link标签本身的跨域能力。
咱们晓得当img或者script中的src是一个链接的时候,浏览器会申请这个链接获取资源,那么这个链接如果是跨域的,浏览器也会申请,从而达到了跨域申请的一个性能。

用法

var script = document.createElement('script');script.src = 'http://localhost:3000/api/test.do?a=1&b=2&callback=cb';$('body').append(script);function cb(res){    // do something    console.log(res)}

能够看到,咱们创立一个script标签,将src改成咱们要申请的接口,并将script增加在body中,那么当浏览器解析到这个script时,会想src对应的服务器发送一个get申请,并将参数带过来。
而后当浏览器接管到服务端返回的数据,就会触发参数中callbak对应的回调函数cb,从而实现整个get申请。

长处
简略粗犷

毛病
①只反对get申请
②须要后盾配合,将返回后果包装成callback(res)的模式

防备
那如果黑客植入script脚本通过jsonp的形式对服务器进行攻打,怎么办?
能够通过页面设置的内容平安协定csp进行防备。

cors跨域
cors 是一个W3C规范,全称是"跨域资源共享"(Cross-origin resource sharing),它容许浏览器向跨源服务器发送XMLHttpRequest申请,从而克服了 AJAX 只能同源应用的限度
cors 须要浏览器和服务器同时反对,整个 CORS通信过程,都是浏览器主动实现不须要用户参加,对于开发者来说,cors的代码和失常的 ajax 没有什么差异,浏览器一旦发现跨域申请,就会增加一些附加的头信息
然而,cors不反对ie10及以下版本。

简略申请和简单申请
浏览器将cors申请分为简略申请和简单申请。
简略申请则间接发送申请到服务器,只申请一次。
而简单申请在正式申请前都会有预检申请,在浏览器中都能看到有OPTIONS申请,用于向服务器申请权限信息的,须要申请两次。

那如何辨别是简略申请还是简单申请呢?

简略申请
简略申请必须要同时满足上面三个条件:

申请形式只能是:GET、POST、HEAD
HTTP申请头限度这几种字段:Accept、Accept-Language、Content-Language、Content-Type、Last-Event-ID
Content-type只能取:application/x-www-form-urlencoded、multipart/form-data、text/plain
content-type的类型
类型形容application/json音讯主体是序列化后的 JSON 字符串application/x-www-form-urlencoded数据被编码为键值对。这是规范的编码格局multipart/form-data须要在表单中进行文件上传时,就须要应用该格局。常见的媒体格式是上传文件之时应用的text/plain数据以纯文本模式(text/json/xml/html)进行编码,其中不含任何控件或格局字符

application/json:

作用: 通知服务器申请的主题内容是json格局的字符串,服务器端会对json字符串进行解析,
益处: 前端人员不须要关怀数据结构的复杂度,只有是规范的json格局就能提交胜利。
application/x-www-form-urlencoded:是Jquery的Ajax申请默认形式

作用:在申请发送过程中会对数据进行序列化解决,以键值对模式?key1=value1&key2=value2的形式发送到服务器。
益处: 所有浏览器都反对。
简单申请
不满足简略申请的条件,那么就是简单申请。
简单申请会在正式申请发送之前,先发一个预检申请进行校验,校验通过后能力进行正式申请。
举个
浏览器当初要发送一个put的简单申请,那么在put申请发送之前,浏览器先发送一个options申请。
options申请头信息:

OPTIONS /cors HTTP/1.1
Origin: localhost:3000
Access-Control-Request-Method: PUT // 示意应用的什么HTTP申请办法
Access-Control-Request-Headers: X-Custom-Header // 示意浏览器发送的自定义字段
Host: localhost:3000
Accept-Language: zh-CN,zh;q=0.9
Connection: keep-alive
User-Agent: Mozilla/5.0...
服务器收到options申请当前,查看了Origin、Access-Control-Request-Method和Access-Control-Request-Headers字段当前,确认容许跨源申请,就能够做出回应
options响应头信息

HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 01:15:39 GMT
Server: Apache/2.0.61 (Unix)
Access-Control-Allow-Origin: http://localhost:3000 // 示意http://localhost:3000能够拜访数据
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: X-Custom-Header
Content-Type: text/html; charset=utf-8
Content-Encoding: gzip
Content-Length: 0
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Content-Type: text/plain
当options申请通过之后收回正式的HTTP申请,假使options申请不通过,则服务器不容许此次拜访,从而抛出谬误

options申请通过之后的,浏览器收回发申请

PUT /cors HTTP/1.1
Origin: http://api.zhenai.com
Host: api.alice.com
X-Custom-Header: value
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...
options申请缓存
那这样的话,如果页面存在大量的简单申请,岂不是每个申请后面都要进行一次options的申请,那不会造成大量资源的节约么?
如果基于cors申请的办法来解决跨域问题,那么简单申请之前是须要进行一个options的申请的,但咱们能够通过对options申请进行缓存来加重申请的压力。

在options申请中,咱们能够通过设置响应头的参数Access-Control-Max-Age来对后果进行缓存
比方: Access-Control-Max-Age: 600 示意对options测验后果进行十分钟的缓存

url变动会导致缓存生效,须要从新验证options申请的返回值
预检不关怀post data
header变动,如果是去掉了自定义的header使得申请变成简略申请,不会发送options申请。如果是减少其余的header,是会从新验证Access-Control-Allow-Headers的值。
cookie变动,只有后端容许发送cookie,cookie值变动不会导致缓存生效。
该字段的兼容性如下:

nginx
nginx解决跨域的问题跟之前的办法有所不同,它是通过服务器的方向代理,将前端拜访域名跟后端服务域名映射到同源的地址下,从而实现前端服务和后端服务的同源,那天然不存在跨域的问题了。
举个 :
前端服务:http://localhost:3000,
前端页面路由:http://localhost:3000/page.html,
后端服务:http://localhost:3001,
后端接口路由:http://localhost:3001/api/test.do
能够看出,两个服务处于跨域的状态
通过nginx的配置进行反向代理,即可实现前后端服务同源,如下:

server{    listen 80;    server_name localhost;    location = / {        proxy_pass http://localhost:3000;    }   location /api {        proxy_pass http://localhost:3001;        #指定容许跨域的办法,*代表所有        add_header Access-Control-Allow-Methods *;        #预检命令的缓存,如果不缓存每次会发送两次申请        add_header Access-Control-Max-Age 3600;        #带cookie申请须要加上这个字段,并设置为true        add_header Access-Control-Allow-Credentials true;        #示意容许这个域跨域调用(客户端发送申请的域名和端口)         #$http_origin动静获取申请客户端申请的域   不必*的起因是带cookie的申请不反对*号        add_header Access-Control-Allow-Origin $http_origin;        #示意申请头的字段 动静获取        add_header Access-Control-Allow-Headers         $http_access_control_request_headers;        #OPTIONS预检命令,预检命令通过时才发送申请        #查看申请的类型是不是预检命令        if ($request_method = OPTIONS){            return 200;        }   }}

其实nginx不仅仅只是用于解决跨域问题,而是波及到很多服务器资源分配的解决,在此就不具体探讨了。

vue proxyTable
其实,在咱们支流应用的MVVM框架中,配置项外面也提供解决跨域问题的能力,持续举个 ,以vue2.x为例,咱们能够通过在config/index.js中增加配置项实现跨域申请:

proxyTable: {    '/apis': {        // 测试环境        target: 'http://www.zhenai.com/',  // 接口域名        changeOrigin: true,  //是否跨域        pathRewrite: {            '^/apis': ''   //须要rewrite重写的,        }     }             }

原理
其实原理很简略,就是在咱们应用npm run dev命中,启动了一个node服务,而后将前端收回的申请发送到node服务,再将该服务转发到本来的后盾服务,在这过程中实现了一层代理,由一个node服务发送一个申请到另外一个后盾服务,天然也没有了浏览器所限度的跨域问题。