为什么会有jsonp
javascript有一个安全限制—-同源策略, 即js只能访问与包含它的文档在同一个域的内容 . 那么这对于ajax影响是 , 通过XMLHttpRequest实现ajax请求不能向不同域提交请求 . 但是随着编程深入 , 会不可避免使用跨域进行请求资源 .
可以实现跨域请求资源的方式 :
- 使用img标签, 因为img标签在页面渲染阶段会向src中的url请求资源 . 以前的系统在统计网站访问量时候会在网页某个地方放一个小图片 , 通过每次图片渲染向服务器发送请求 , 从而能判断网站是否被访问 .
- iframe请求服务端, 并接受返回数据 . 可以通过隐藏iframe标签 , 接收返回数据并进行处理 , 但是这种方式处理比较复杂 .
使用link标签, rel是stylesheet , 也就是类似于请求css文件的方式 , 但是这种方式会使页面在渲染过程出现css错误 .
使用script方式, 类似于请求js文件 .
分析script这种方式
- 当向豆瓣API发送”https://api.douban.com/v2/movie/in_theaters?count=1&callback=func“这样一条请求, 返回的数据假如如下:
- 如果我们本地定义一个全局函数如下:
- 那么当script请求到数据之后,我们本地的func函数就会执行,而data也就是script返回数据func的参数
- 如何让其他系统返回 func(name:zhangsan,age:22) 这种数据 ,注意到我们的url有一个参数 : callback , 其他系统会根据这个参数对应的值,拼出对应的数据 , 并返回给我们.当然豆瓣API只识别callback参数, 其他系统可能有其他形式参数 .
手写自己的jsonp
- html代码 :
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="result"></div>
</body>
<script type="text/javascript" src="jsonp.js"></script>
<script type="text/javascript">
$jsonp("https://api.douban.com/v2/movie/in_theaters",{count:10},function (data) {
document.getElementById("result").innerHTML = JSON.stringify(data);
});
</script>
</html>
2.js代码(jsonp.js)
/**
1. Created by 张延 on 2017/1/18.
*/
(function (window, document, undefined) {
/**
*
* @param url 请求的数据
* @param data 需要传递的数据
* @param callback 回调执行的函数
*/
var jsonp = function(url, data, callback) {
// 1.自定义一个函数名
var callBackFuncName = "jsonp_callback_"+Math.random().toString().replace(".","");
// 2.将这个函数防止到window全局上
window[callBackFuncName] = callback;
// 3.定义一个queryString字符串,将data变为字符串
var queryString = url.indexOf("?") == -1 ? "?" : "&";
for(var key in data) {
queryString += key + "=" + data[key] + "&" ;
}
// callback : 取决调用API规范的参数名
queryString += "callback=" + callBackFuncName;
// 4.创建script节点, 并将url+queryStirng设置为src
var scriptElement = document.createElement("script");
scriptElement.src = url + queryString;
// 将这个script节点拼接到body中
document.body.appendChild(scriptElement);
}
window.$jsonp = jsonp;
})(window, document);
3. 页面效果(将请求到json数据渲染到页面)