什么是跨域:
跨域是浏览器同源策略而产生的,在不同协议,不同端口,不同域名下(以上任意一个不同都算是跨域)的客服端和服务端之间是无法互相访问的。
举例:
http://www.baidu.com/index.html 调用 http://www.baidu.com/server.php (非跨域)
http://www.baidu.com/index.html 调用 http://www.csdn.com/server.php (主域名不同:,跨域)
http://abc.baidu.com/index.html 调用 http://def.baidu.com/server.php (子域名不同:abc/def,跨域)
http://www.baidu.com:8080/index.html 调用 http://www.baidu.com:8081/server.php (端口不同:8080/8081,跨域)
http://www.baidu.com/index.html 调用 https://www.baidu.com/server.php (协议不同:http/https,跨域)
请注意:localhost和127.0.0.1虽然都指向本机,但也属于跨域。
jsonp原理:
先来看下一个例子:用node在本地搭两个服务,一个处理调用html页面(server1端口:8081),一个用来访问服务下的静态资源(server2端口:8082)。代码如下
server1
let express = require('express');
var app = express();
app.get('/index.html',function(req,res){
res.sendFile(__dirname+'/'+'index.html');
})
var server = app.listen(8081,function(){
var host = server.address().address;
var port = server.address().port;
console.log("应用实例,访问地址为http://%s:%s", host, port);
});
复制
server2
let express = require('express');
var app = express();
app.get('/',function(req,res){
res.send('hello word!!!!');
})
app.use(express.static(__dirname));
var server = app.listen(8082,function(){
var host = server.address().address;
var port = server.address().port;
console.log("应用实例,访问地址为http://%s:%s", host, port);
});
复制
这样就可以来访问server1下的index.html文件以及server2下的静态资源了。接下来我在server2下放了个callback.js文件,然后写了alert(‘hello jsonp!!!’),因为两个服务的端口不一样,存在跨域问题,在server1中的index.html是没办法直接访问server2下的callback.js文件的。但是如果我们用script的src来引用确是可以的(<script src=”http://localhost:8082/callback.js”></script>),如下
没错,jsonp跨域利用的其实就是script的src属性,这个属性不受同源策略影响,可以访问不同服务下的资源。我们来修改下server2下的callback.js文件,如下
callback({
name:'jsonp',
server:'server2',
content:'hello jsonp!!!'
})
复制
然后server1下的index.html这样写
<!DOCTYPE >
<html>
<head>
<meta charset="utf-8" >
<title>jsonp 跨域原理</title>
<style>
.wrap{ width: 800px; margin: 100px auto;}
</style>
</head>
<body>
<div class="wrap">
<h1>jsonp跨域原理。。。</h1>
</div>
<script>
function callback(data){
console.log(data);
}
</script>
<script src="http://localhost:8082/callback.js"></script>
</body>
</html>
复制
然后浏览器访问:localhost:8081/index.html,结果如下
获取到server2服务端的数据了,这是jsonp的简单原理。
接下来再改进一下,server2下创建一个dada.json的数据,如下:
然后读取这个文件,并获取客户端传过来的cb参数,然后包裹数据返回给客户端,代码如下:
let express = require('express');
let fs = require('fs');
let url = require('url');
let querystring = require('querystring');
var app = express();
app.get('/',function(req,res){
res.send('hello word!!!!');
})
app.use(express.static(__dirname));
app.get('/getdata',function(req,res){
//同步读取json文件
var data = fs.readFileSync('server2/data.json').toString();
//console.log(data);
var qs = url.parse(req.url).query;
var cb = querystring.parse(qs).cb;
var jsonp = cb+"("+data+")";
res.send(jsonp);
});
var server = app.listen(8082,function(){
var host = server.address().address;
var port = server.address().port;
console.log("应用实例,访问地址为http://%s:%s", host, port);
});
复制
最后在客户端server1的index.html中这样修改:
<!DOCTYPE >
<html>
<head>
<meta charset="utf-8" >
<title>jsonp 跨域原理</title>
<style>
.wrap{ width: 800px; margin: 100px auto;}
</style>
</head>
<body>
<div class="wrap">
<h1>jsonp跨域原理。。。</h1>
</div>
<script>
function callback(data){
console.log(data);
}
var scriptDom = document.createElement('script');
scriptDom.src = "http://localhost:8082/getdata?cb=callback";
document.body.appendChild(scriptDom);
</script>
<!--<script src="http://localhost:8082/callback.js"></script>-->
</body>
</html>
复制
浏览器访问:localhost:8081/index.html 如下:
成功获取8082端口下的data.json数据。
结论:
jsonp通过在服务端用一个回调函数把数据一起包裹起来并返回给客户端(jsonp名字就是这样来的json padding),然后客户端写好回调(处理数据),并动态创建一个script节点,通过src属性来调用服务端返回的回调函数。