什么是同源策略
浏览器出于安全的方面考虑,只允许同协议,同域名,同端口下的接口交互,不同源的客户端脚本在没有授权的情况下,不能读写未授权方的资源.
同源的条件
- 同协议:比如都是http,或者都是https
- 同域名:比如baidu.com/a ,baidu.com/b
- 同端口:比如80端口
什么是跨域? 有哪些方式
- JSOP
- CORS 跨域资源共享(Cross-Origin Resource Sharing)
- 降域
- postMessage()
CORS的原理
CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)。
它允许浏览器向跨源服务器,发出[XMLHttpRequest]请求,从而克服了AJAX只能[同源]使用的限制。
CORS重点是需要后端支持才行.
简单模式:GET POST HEAD
HTTP的头信息不超出以下几种字段
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain
后端添加响应头
response.setHeader('Access-Control-Allow-Origin','http://xxxx.com') // 允许xxxx.com跨域请求
简单请求:对于简单请求,浏览器直接发出CORS请求。具体来说,就是在头信息之中,增加一个Origin字段。
Origin:http://xxx.com:8888
来自源(协议,域名,端口)服务器根据这个值,决定是否同意这次请求。
如果Origin指定的源,不在许可范围内,服务器会返回一个正常的HTTP回应。浏览器发现,这个回应的头信息没有包含Access-Control-Allow-Origin字段,就知道出错了,从而抛出一个错误,被XMLHttpRequest的onerror回调函数捕获。注意,这种错误无法通过状态码识别,因为HTTP回应的状态码有可能是200。
复杂模式: 除了GET POST HEAD
后端添加响应头
response.setHeader('Access-Control-Allow-Origin','http://xxxx.com') // 允许xxxx.com跨域请求
response.setHeader('Access-Control-Allow-Methods','GET,POST,HEAD,PUT,PATCH,OPTIONS,DELETE'
运用方式
- 更改本地hosts,映射本地访问 (Mac用sudo方式更改,windows用管理员运行记事本打开hosts更改)
127.0.0.1 cheche.com
127.0.0.1 duowan.com
- 使用nodejs执行index.js,监听80端口 (Mac用sudo方式更改80端口,windows用管理员运行gitbush更改80端口),并且添加响应头
response.setHeader('Access-Control-Allow-Origin','http://duowan.com')
,response.setHeader('Access-Control-Allow-Method','get,post,head')
让duowan.com获得跨域请求权限 - 访问http://cheche.com/cheche,发送AJAX请求http://cheche.com/cheche_prototype.JSON
- 访问http://duowan.com/duowan,发送AJAX请求http://cheche.com/cheche_prototype.JSON,这样实现http://duowan.com对http://cheche.com跨域请求
具体详情参考阮一峰非简单请求
JSONP
原理:就是利用<script>
标签没有跨域限制来达到与第三方通讯的目的。当需要通讯时,本站脚本创建一个<script>
元素,地址指向第三方的API网址,形如:
<script src="http://www.example.net/api?param1=1¶m2=2"></script>
并提供一个回调函数来接收数据(函数名可约定,或通过地址参数传递)。
第三方产生的响应为json数据的包装(故称之为jsonp,即json padding),形如:
callback({"name":"cheche","gender":"Male"})
这样浏览器会调用callback函数,并传递解析后json对象作为参数。本站脚本可在callback函数里处理所传入的数据。
实例
运行方式
- 使用node.js执行index.js监听80端口
- 更改本地hosts文件,映射本地访问为
127.0.0.1 cheche.com
127.0.0.1 duowan.com
- 访问http://cheche.com, script会请求
http://duowan.com/duowan.js
具体实现代码
- 声明封装一个jsonp的函数,并且传入两个参数url和一个随机的Messagexxx,因为防止多次跨域请求得到的资源不会被覆盖.让每一次请求的资源都能够独立的显示.
function jsonp(url,fn){
var Message = 'Message'+parseInt(Math.random()*1000,10) //生成随机Message
window[Message] = fn //让这个随机Message是window中的key,这里不使用window.Message主要是因为这个Message是随机每一都不一样.
var script = document.createElement('script') //创建一个script标签
script.src = url+'?callback='+ Message //callback是约定俗成的,可以改变为任意参数
document.head.appendChild(script) //利用script的特性,只有在html文档中才会触发请求
}
-
在duowan.js中放入要被跨域请求的数据
{{callback}}({"name":"cheche","gender":"male"})
//{{callback}}是一个占位等待被回调的参数 -
在后端中需要添加如下代码
if(path === "/duowan.js"){
var string = fs.readFileSync('./duowan.js','utf-8')
var callback = query.callback //利用?查询字符串调取callback的值,这个值就是Message看上边步骤1
response.setHeader('Content-Type','charset=utf-8')
response.end(string.replace('{{callback}}',callback)) //替换string字符串中的{{callback}}为callback,它的值又是Message,Message在window中它的值是function(data){}
}
- 在前端执行jsonp函数
jsonp('http://duowan.com',function(data){
console.log(第一次数据)
console.log(data)
})
jsonp('http://duowan.com',function(data){
console.log(第二次数据)
console.log(data)
})
- 得到响应的数据为Message加随机数的执行函数:Message0323({"name":"cheche","gender":"male"})
第一次的数据
{"name":"cheche","gender":"male"}
第二次的数据
{"name":"cheche","gender":"male"}
jQuery也有同样的函数实现JSONP
$.ajax({
url:"http://duowan.com/duowan.js"
dataType:'jsonp'
success:function(data){
console.log('第一次执行')
console.log(data)
}
})
CORS与JSONP的使用目的相同,但是比JSONP更强大。
JSONP只支持GET请求,CORS支持所有类型的HTTP请求。JSONP的优势在于支持老式浏览器,以及可以向不支持CORS的网站请求数据。
网友评论