json和jsonp缩写只相差一个字母,可是二者却彻底不一样。前者是一种数据的表达方式,后者则是网络请求的一种解决方案。javascript
使用ajax发送网络请求有一个条件,那就是同源策略。php
同源策略要求:java
http
、https
、ftp
等等https://www.baidu.com/
或者本身的主机ip地址8080
、80
等等例如日常使用webstorm进行调试的时候,webstorm会开一个本地服务器http://localhost:63342/xxxx
,可是若是你使用ajax去访问https://www.baidu.com/
之类的服务器你是没法拿到数据的。实际上浏览器已经拿到数据,可是作了一层隔离,不给你数据。node
在说原理以前首先要了解两个关于<script>
的特色web
<script>
标签可使用cdn加速(根据浏览器所在网络地区,从最近的服务器下载js脚本,通常下载框架和库),那么cdn的服务器毫无疑问是不一样源的。因此,<script>
标签能够跨域访问别的服务器。<script>
标签是经过src
节点属性获取js代码的,而且获取到的代码能够直接执行。在了解了上面的2个<script>
的特色以后大概都能猜出来,jsonp就是使用<script>
以上两个特色来实现的,具体的实现方式有2种。ajax
方式一编程
<script>
标签发送请求,拼接上callback=方法名
参数。callback
参数,拿到方法名后在方法名后拼接()
,而且传入返回的数据这种方式对于php来讲就是字符串拼接,可是传回来的时候则是被js解析成调用对应的方法了。json
// php $res = file_get_contents($url); $func = $_GET[callback]; echo callback.'('.$res.')';
方式二后端
jsonp不管如何都要后端支持(要么是本身的后端写的php,要么是别人接口支持jsonp跨域的回调方法),不然没法使用。api
// 1. 建立一个script标签 var script = document.createElement('script'); // 2. 随机生成一个方法 // 用时间戳做为种子,这样随机生成的方法名绝对没有重复的。 var funcName = 'jsonpFunc' + Math.floor(new Date().getTime() * Math.random()); window[funcName] = function (json) { console.log(json); // 把请求完的标签从文档中移除 document.head.removeChild(script); }; // 3. 拼接请求地址,加上回调 script.src = 'http://api.douban.com/v2/movie/in_theaters?callback=' + funcName; // 4. 把script标签放到文档中,就会发送请求 document.head.appendChild(script);
封装一下:
window.myJsonp = function (opt) { // 简单的容错 if (!opt || !opt.url) return; opt.callback = opt.callback || 'callback'; opt.params = opt.params || {}; opt.callback = opt.callback || function () {}; // 1. 建立一个script标签 var script = document.createElement('script'); // 2. 随机生成一个方法 var funcName = 'jsonpFunc' + Math.floor(new Date().getTime() * Math.random()); window[funcName] = function (json) { // 5. 把请求完的标签从文档中移除 document.head.removeChild(script); // 6. 删除添加到window的方法名称,避免污染 delete window[funcName]; // 7. 把获取到的数据经过回调的方式传出去 opt.callback(json); }; // 3. 拼接请求地址,加上回调(参数拼接和get请求一致) var params = ''; for (var key in opt.params) { params += key + '=' + opt.params[key] + '&'; } script.src = opt.url + '?' + params + 'callback=' + funcName; // 4. 把script标签放到文档中,就会发送请求 document.head.appendChild(script); }; // 使用 myJsonp({ url: 'http://api.douban.com/v2/movie/in_theaters', callback: function (json) { console.log(json); } });
待续。。。