共计 4972 个字符,预计需要花费 13 分钟才能阅读完成。
同源策略
同源策略,它是由 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 服务发送一个申请到另外一个后盾服务,天然也没有了浏览器所限度的跨域问题。