https://segmentfault.com/a/1190000015597029
https://www.jianshu.com/p/2283ed2751d9
JavaScript出于安全考虑,不允许跨域调用其他页面的对象。
3.服务器端解决【在响应头上(header)加上:Access-Control-Allow-Orign:允许的网址,如果写*则代表所有】
注意:是js中去主动创建一个script标签,然后src属性里写请求的地址。在一般情况下,服务器会根据Accept【是请求头中的一个字段】的值,来决定返回的数据的类型,并设置Content-Type【是响应头中的一个字段】,通常Content-Type的值和Accept的第一个值相等
jsonp:是一种非官方跨域数据交互协,是一种解决跨域请求的方案。jsonp是json with paramter的简称,即:json通过参数的形式给到你。
2.调用一下jsonp接口:调用方式-》创建一个script标签-》url链接中&_jsonp=函数名-》将script追加到页面【script执行的结果就是一个函数,其实是将函数调用追加到页面】
$.ajax({ type:"get", url:"./jquery_jsonp.php", dataType:"jsonp", jsonpCallback:"callback" success:function(json){ console.log(json); }, error:function(data){ console.log(data); console.log(456); } }); callback(data);
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <script> // 必须放在全局作用域内,不能放在自执行函数里 function abc(data) { document.write(data); } </script> <!-- 下面script标签的执行结果即:abc(["a","b","c"]) --> <script src="./jsonp.php?_jsonp=abc"></script> </head> <body> </body> </html>
<?php $_jsonp = $_GET['_jsonp']; $arr = array("a","b","c"); echo $_jsonp.'('.json_encode($arr).')'; ?>
通过一个script标签发送请求,返回的是一个js脚本。也就是说上面的请求服务器返回的js脚本是:
abc(['a','b','c'])
这个脚本被请求到后立即被执行,当执行到abc函数时,就会在全局作用域里去找一个abc的方法,找到了就去执行。
img、iframe、link、script都可以做跨域,他们每一个在js中都是一个对象。
<!--统计链接,支持跨域但是无法实现获取服务器端返回的数据--> <img src="" alt=""> <!--支持跨域,可以接收服务器端数据,但是过程复杂--> <iframe src="" frameborder="0"></iframe> <!--支持跨域,会在css处理阶段报错--> <link rel="stylesheet" href=""> <!--最方便的使用跨域的方式,要求跨域函数必须是全局的,不能放在自执行函数里--> <script src=""></script>
// jsonpSev.js 'use strict'; /* 自己实现一个jsonp的服务,仿照创建script的方式 1.创建回调函数,挂载到全局 2.拼接jsonp格式的url 3.创建script,并添加到页面 */ (function (window, document) { /* @url:请求地址 http://api.douban.com/v2/movie/top250 @data:请求参数 {start:0,count:25} */ var jsonpfun = function (url, data, callback) { /*1.创建回调函数,挂载到全局*/ var cnName = 'cb_jsonp_' + (+new Date()); window[cnName] = callback; /*2.拼接jsonp格式的url*/ var suffix = url.indexOf('?') != -1 ? 'callback=' + cnName : '?callback=' + cnName; for (var k in data) { suffix += '&' + k + '=' + data[k]; } /*3.创建script,并添加到页面*/ var script = document.createElement('script'); script.src = url + suffix; document.querySelector('body').appendChild(script); } })(window, document);
上面代码有一个问题:就是每次点击下一页都会创建一个script,而这个script在加载过后就不在起作用,这就造成了页面中大量无用的script标签。改进写法:
'use strict'; /* 自己封装angular的jsonp, 原由:豆瓣不支持angular封装的jsonp格式,由于angular封装的 以不污染全局为思想,将jsonp的回调函数封装在angular.callback 中,而且回调函数命名为angular.callback._0(),豆瓣不支持 */ (function (angular) { var $jsonp = angular.module('jsonpSev', []); $jsonp.service('$jsonp', ['$window', '$document', function ($window, $document) { /* * 创建自己的jsonp * 1.创建callback函数,挂载到全局 * 2.拼接url => url?name=xx&age=xx * 3.创建script,添加到页面 * */ this.jsonp = function (url, params, callback) { // 1.创建callback函数,挂载到全局[放在后面挂载了] var cbName = 'jsonp_callback_' + (+new Date()); // 2.拼接url var suffix = url.indexOf('?') != -1 ? 'callback=' + cbName : '?callback=' + cbName; for (let d in params) { suffix += '&' + d + '=' + params[d]; } // 3.创建script,添加到页面 var script = $document[0].createElement('script'); script.src = url + suffix; // 把挂载到全局放在创建script后面,因为马上我们要移除 // 这个script[当这个script请求的脚本呗执行后,这个script不在有用] $window[cbName] = function (data) { callback(data); $document[0].querySelector('body').removeChild(script); }; $document[0].querySelector('body').appendChild(script); } }]) })(angular);