跨域,指的是浏览器不能执行其余网站的脚本。 它是由浏览器的同源策略形成的,是浏览器施加的安全限制。 所谓同源策略是指,协议、端口、域名都相同。javascript
浏览器的同源策略会致使跨域,这里同源策略又分为如下两种:html
浏览器执行脚本时,会检查脚本是否同源,若是不是,则不会被执行。java
两个域名不能跨过域名来发送数据和请求数据,不然就是不安全的,这种不安全也就是CSRF
(跨站请求伪造)攻击。jquery
若是没有AJAX同源策略,至关危险,咱们发起的每一次HTTP请求都会带上请求地址对应的cookie,CSRF
攻击是利用用户的登陆态发起恶意请求。web
JSONP的产生:ajax
AJAX直接请求普通文件存在跨域无权限访问的问题,不论是静态页面也好.json
不过咱们在调用js文件的时候又不受跨域影响,好比引入jquery框架的,或者是调用相片的时候api
凡是拥有src这个属性的标签均可以跨域例如<script>
<img>
<iframe>
跨域
若是想经过纯web端跨域访问数据只有一种可能,那就是把远程服务器上的数据装进js格式的文件里.浏览器
而json又是一个轻量级的数据格式,还被js原生支持
为了便于客户端使用数据,逐渐造成了一种非正式传输协议,人们把它称做JSONP,该协议的一个要点就是容许用户传递一个callback 参数给服务端。
基于script
跨域
<script src="http://domain/api?param1=a¶m2=b&callback=jsonp"></script>
<script>
function jsonp(data) {
console.log(data)
}
</script>
复制代码
在开发中可能会遇到多个 JSONP 请求的回调函数名是相同的,这时候就须要本身封装一个 JSONP,如下是简单实现:
function jsonp(url, jsonpCallback, success) {
let script = document.createElement('script')
script.src = url
script.async = true
script.type = 'text/javascript'
window[jsonpCallback] = function(data) {
success && success(data)
}
document.body.appendChild(script)
}
jsonp('http://xxx', 'callback', function(value) {
console.log(value)
})
复制代码
基于jQuery
跨域
$.ajax({
url:'http://domain/api',
ype : 'get',
dataType : 'text',
success:function(data){
alert(data);
},
error:function(data){
alert(2);
}
});
复制代码
经过iframe
来跨子域
eg: a.study.cn/a.html 请求 b.study.cn/b.html
a.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script type="text/javascript">
document.domain = 'study.cn';
function test() {
alert(document.getElementById('a').contentWindow);
}
</script>
</head>
<body>
<iframe id='a' src='http://b.study.cn/b.html' onload='test()'>
</body>
</html>
复制代码
b.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script type="text/javascript">
document.domain = 'study.cn';
</script>
</head>
<body>
我是b.study.cn的body
</body>
</html>
复制代码
修改document.domain的方法只适用于不一样子域的框架(父类与子类)间的交互。
支持CORS请求的浏览器一旦发现ajax请求跨域,会对请求作一些特殊处理,对于已经实现CORS接口的服务端,接受请求,并作出回应。
有一种状况比较特殊,若是咱们发送的跨域请求为“非简单请求”,浏览器会在发出此请求以前首先发送一个请求类型为OPTIONS的“预检请求”,验证请求源是否为服务端容许源,这些对于开发这来讲是感受不到的,由浏览器代理。
总而言之,客户端不须要对跨域请求作任何特殊处理。
浏览器对跨域请求区分为“简单请求”与“非简单请求”
简单请求
(1) 请求方法是如下三种方法之一:
HEAD
GET
POST
复制代码
(2)HTTP的头信息不超出如下几种字段:
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type:
application/x-www-form-urlencoded、 multipart/form-data、text/plain
复制代码
不知足这些特征的请求称为“非简单请求”,例如:content-type=applicaiton/json , method = PUT/DELETE...
浏览器判断跨域为简单请求时候,会在Request Header中添加 Origin (协议 + 域名 + 端口)字段 , 它表示咱们的请求源,CORS服务端会将该字段做为跨源标志。
必须字段:
Access-Control-Allow-Origin:表示服务端容许的请求源,*标识任何外域,多个源 , 分隔
可选字段
Access-Control-Allow-Credentials:false 表示是否容许发送Cookie,设置为true
同时,ajax请求设置withCredentials = true,浏览
器的cookie就能发送到服务端
Access-Control-Expose-Headers:调用getResponseHeader()方法时候,能从header中获
取的参数
复制代码
总结:简单请求只须要CORS服务端在接受到携带Origin字段的跨域请求后,在response header中添加Access-Control-Allow-Origin等字段给浏览器作同源判断
进行非简单请求时候, 浏览器会首先发出类型为OPTIONS的“预检请求”,请求地址相同 , CORS服务端对“预检请求”处理,并对Response Header添加验证字段,客户端接受到预检请求的返回值进行一次请求预判断,验证经过后,主请求发起。
例如:发起 content-type=application/json 的非简单请求,这时候传参要注意为json字符串
这里能够看到,浏览器连续发送了两个jsonp.do请求 , 第一个就是“预检请求”,类型为OPTIONS,由于咱们设置了content-type这个属性,因此预检请求的Access-Control-Expose-Headers必须携带content-type,不然预检会失败。
预检经过后,主请求与简单请求一致。
总结:非简单请求须要CORS服务端对OPTIONS类型的请求作处理,其余与简单请求一致
经过上面叙述,咱们得知借助CORS咱们没必要关心发出的请求是否跨域,浏览器会帮咱们处理这些事情,可是服务端须要支持CORS,服务端实现CORS的原理也很简单,在服务端彻底能够对请求作上下文处理,已达到接口容许跨域访问的目的。
浏览器有跨域限制,可是服务器不存在跨域问题,因此能够由服务器请求所要域的资源再返回给客户端。
该方式只能用于二级域名相同的状况下,好比 a.test.com 和 b.test.com 适用于该方式。
只须要给页面添加 document.domain = 'test.com' 表示二级域名都相同就能够实现跨域。
location.hash方式跨域,是子框架具备修改父框架src的hash值,经过这个属性进行传递数据,且更改hash值,页面不会刷新。可是传递的数据的字节数是有限的。
页面和新开的窗口的数据交互。
这个应该就是之后解决dom跨域通用方法了,具体能够参照MDN。
// 发送消息端
window.parent.postMessage('message', 'http://test.com')
// 接收消息端
var mc = new MessageChannel()
mc.addEventListener('message', event => {
var origin = event.origin || event.originalEvent.origin
if (origin === 'http://test.com') {
console.log('验证经过')
}
})
复制代码
参考: