前言
在开发过程中往往会遇到js跨域问题,在面试中跨域几乎是必考题。js跨域有很多方式,jsonp只是其中一种,许多人对jsonp似懂非懂,下面说一下js跨域原因以及jsonp原理。
同源策略
为安全考虑,Netscape提出了同源策略 Same-Origin-Policy(SOP)。url组成包括协议名,子域名,主域名,端口号只要协议,域名,端口有任何一个的不同,就被认为是跨域,即禁止页面加载或执行与自身来源不同的域的任何脚本。即使是 localhost:8080 请求 127.0.0.1:8080 也会被认为是跨域。
实现跨域有很多种方法:
- 服务端代理
- 服务端返回响应头Access-Control-Allow-Origin
- jsonp
- iframe嵌入页面
- html5 postMessage
jsonp原理
我们直接用XMLHttpRequest请求不同域上的数据时,是不可以的。但是,在页面上引入不同域上的js脚本文件却是可以的,jsonp正是利用这个特性来实现的。
浏览器中script、img、iframe、link这些包含 src 属性的标签可以加载跨域资源。但浏览器限制了JavaScript的权限使其不能读、写加载的内容。
简单来说,jsonp就是动态添加script标签引入src来实现跨域。
原生js1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41//客户端
function addScriptTag(src) {
var script = document.createElement('script');
script.setAttribute('type', 'text/javascript');
script.src = src;
document.body.appendChild(script);
};
//如:在onload后,跨域请求
window.onload = function () {
addScriptTag('http://127.0.0.1:8080?callback=callback');
};
//回调的方法,且必须为全局方法,不然会报错
function callback(data) {
console.log(data);
};
//服务端 node.js
var http = require('http');
var url = require('url');
var querystring = require('querystring');
var server = http.createServer();
server.on('request', function (req, res) {
console.log(url.parse(req.url));
var urlPath = url.parse(req.url).pathname;
var qs = querystring.parse(req.url.split('?')[1]);
console.log(qs);
if (qs.callback) {
res.writeHead(200, {'Content-Type': 'application/json;charset=utf-8'});
var data = {
"name": "hugh dai"
};
data = JSON.stringify(data);
var callback = qs.callback+'('+data+');';
res.end(callback);
}
else {
res.writeHead(200, {'Content-Type': 'text/html;charset=utf-8'});
res.end('Hell World\n');
}
})
server.listen('8080');
console.log('Server running...');
jquery实现1
2
3
4
5
6
7
8
9
10
11
12
13
14$.ajax({
type: "get",
async: false,
url: "http://127.0.0.1:8080",
dataType: "jsonp",
jsonpCallback:"callback", //callback函数(jsonp回调函数,默认是callback)
success: function(data){
//如果有callback函数的话两者都会执行
console.log(data);
},
error: function(){
console.log('fail');
}
});