跨域解决方案之JSONP
在项目开发中,前端请求后端接口常常会遇到跨域问题,我们前端通常的做法是通过反向代理或者JSONP来解决。JSONP中,我们要把接口和字段(字段通常包括 json数据 和 回调的方法...)写在 script 标签的 src 的属性值中,由于script 的 src 属性不受同源策略的限制,所以当 src 的属性值是我们要请求的接口和字段时,自然也就可以跨域访问。
JSONP其实就是使用回调函数的原理,结合不受同源约束的 src 属性来实现跨域请求的。
通过动态创建script标签,给 src 传递不同参数,获取后端返回的不同的数据,这个数据形如 getInfo({'name':'edward'}),然后将这个script标签插入到当前代码中。
当我们成功获取到后台返回来的数据时,相当于调用了一次前端事先创建好的回调函数,这就是JSONP的大体流程。
同源策略
同源策略(Same origin policy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。
同源策略,它是由Netscape提出的一个著名的安全策略。
现在所有支持JavaScript 的浏览器都会使用这个策略。所谓同源是指,域名,协议,端口相同。
例如:
http://www.baidu.com 和 http://www.baidu.com:8080 二者是不同源的。
http://www.baidu.com和https://www.baidu.com 同样是不同源的。
当请求不同源的数据的时候,浏览器就会在控制台报出一个异常,并且提示拒绝访问。同源策略是浏览器的行为,是为了保护本地数据不被JavaScript代码获取回来的数据污染,因此拦截的是客户端发出的请求回来的数据接收,即请求发送了,服务器响应了,但是无法被浏览器接收。
JSONP介绍
JSONP(JSON with Padding)是JSON的一种“使用模式”,可用于解决主流浏览器的跨域数据访问的问题。由于同源策略,一般来说位于 server1.example.com 的网页无法与不是 server1.example.com的服务器沟通,而 HTML 的 元素是一个例外。利用 元素的这个开放策略,网页可以得到从其他来源动态产生的 JSON 资料,而这种使用模式就是所谓的 JSONP。用 JSONP 抓到的资料并不是 JSON,而是任意的JavaScript,用 JavaScript 直译器执行而不是用 JSON 解析器解析。
JSONP基本原理
上面简单的理解了JSONP的功能之后,下面来一点一点的了解JSONP的具体使用方式。
首先通过script
标签引入一个指定的文件。
例如1.txt中有一个数组。
["hello","world"]
为了使用这个数组,我们通过JSONP的逻辑,使用script
标签引入这个文件
<script src="01.txt"></script>
上面我们虽然引入了这个文件,但是我们发现引入后我们并没有办法使用。我们之前曾经做过类似于下面的行为,就是给数据前面添加一个变量名。类似于下面:
var a = ["hello","world"]
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="01.txt"></script>
<script>
alert(a);
</script>
</head>
<body>
</body>
</html>
上面的代码顺利的读取了文件中的数据。
但是程序开发当中,我们如果采取类似于像上面的写法,又可能造成变量的污染。
既要解决读取数据的问题,又要避免变量污染,我们可以采取函数的形式。
将01.txt改成下面的形式:
fn(["hello","world"])
在网页文件中如下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> <script> function fn(data){ alert(data); } </script> <script src="01.txt"></script> </body> </html>
上面的代码中,当文件被加载进来的时候,就相当于调用了我们定义好的函数fn,而文件中的数据也自动的被传入到了函数中。
接下来,我们模拟一下动态创建 script 标签时,访问后台数据的场景:
当我们点击按钮后,控制台打印结果为:'张三' 52,表明回调成功。
上面代码的逻辑就是JSONP的核心逻辑。
添加请求参数
在上面的代码中,我们简单的体验了JSONP的基本逻辑。下面我们来将基本的使用方式进行一下升级,让我们的请求能够添加参数。
例如,我们现在在服务端中有两组数组,一组存储的是歌名,一组存储的是电影名,点击不同的按钮显示不同的数据。
首先我们先来完成html的代码:
<button id="btn1">音乐排行</button> <ul id="list1"> </ul> <button id="btn2">电影排行</button> <ul id="list2"> </ul>
我们的需求是点击两个按钮分别显示不同的数据,下面是服务端的代码:
<?php header("Content-type:text/html;Charset=utf-8"); // 接收数据 $parm = $_GET['parm'] ? $_GET['parm'] : 'music'; $callback = $_GET['callback']; // 模拟数据库存储的数组 $arr_music = ['残酷月光','孤身','Come back','情深深雨蒙蒙','救赎']; $arr_movie = ['肖申克的救赎','流浪地球','盗梦空间','我不是药神','阿甘正传']; // 判断传输的数据是什么 if($parm === "music") { $data = $arr_music; }else { $data = $arr_movie; } // 传输数据 echo $callback . "(" . json_encode($data) . ")"; // 将数据传输之前转换成json
JS代码:
// 点击按钮请求数据 let oBtn1 = document.getElementById('btn1'); let oBtn2 = document.getElementById('btn2'); // 创建回调函数 function getdata1(data) { // 获取元素赋值 let list1 = document.getElementById('list1'); html = ''; for(let i=0;i<data.length;i++){ html += "<li>" + data[i] + "</li>"; } list1.innerHTML = html; } function getdata2(data) { // 获取元素赋值 let list2 = document.getElementById('list2'); html = ''; for(let i=0;i<data.length;i++){ html += "<li>" + data[i] + "</li>"; } list2.innerHTML = html; } oBtn1.onclick = ()=> { // 创建script标签 ,动态插入 let script = document.createElement('script'); // 创建 let url = "02.jsonp.php?parm=music&callback=getdata1"; script.src = url; document.getElementsByTagName('body')[0].appendChild(script); }; oBtn2.onclick = ()=> { // 创建script标签 ,动态插入 let script = document.createElement('script'); // 创建 let url = "02.jsonp.php?parm=movie&callback=getdata2"; script.src = url; document.getElementsByTagName('body')[0].appendChild(script); };
这样,我们就通过JSONP的形式读取到了后台文件的数据。
JSONP因为通过src属性,所以只能通过get传输数据。
小练习:百度搜索提示
首先,我们可以使用下面的百度接口来实现:
http://suggestion.baidu.com/su
想要使用这个接口需要设置两个参数:
wd 要搜索的内容
cb 回调函数
我们首先在页面当中实现一个输入框:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>百度</title> </head> <body> <input type="text" id="q" placeholder="请输入要搜索的内容"> <button id="btn">搜索</button> <ul id="list"> </ul> </body> </html>
下面是js代码:
function fn(data) { var oUl = document.getElementById('list'); var html = ''; if (data.s.length) { oUl.style.display = 'block'; for (var i=0; i<data.s.length; i++) { html += '<li><a target="_blank" href="http://www.baidu.com/s?wd='+data.s[i]+'">'+ data.s[i] +'</a></li>'; } oUl.innerHTML = html; } else { oUl.style.display = 'none'; } } let q = document.getElementById('q'); let oUl = document.getElementById('list'); q.onkeyup = function(){ if ( this.value != '' ) { var oScript = document.createElement('script'); oScript.src = 'http://suggestion.baidu.com/su?wd='+this.value+'&cb=fn'; document.body.appendChild(oScript); } else { oUl.style.display = 'none'; } }
作者:牧羊狼
出处:https://www.cnblogs.com/edwardwzw/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利,谢谢您的配合。
Freedom is not let you do whatever you wanna but teach you not to do the things that you donnot wanna do.