封装-Jsonp

Jsonp

jsonp是什么?

  • 通过script标签中的src属性没有同源限制的方法进行获取数据

即通过script标签来跨域获取数据,名为JSON with Padding,
或者就叫JSONP。JSONP的原理很简单,但需要服务器端给予相应配合。
大致来说,JSONP的实现思路就是在客户端编程时作好使用JSON数据的准备,然后再通过圆括号将这些数据括起来以创建一条有效的JavaScript语句(可能是一次有效的函数调用)。

也就是说,客户端可以使用一个用于命名jsonp的查询参数来决定可以获取的数据。最简单的情况下,如果jsonp参数为空,则返回的数据就是被括在圆括号中的JSON

为什么使用jsonp?

浏览器安全模型规定,XMLHttpRequest、框架(frame)等只能在一个域中通信。
从安全角度考虑,这个规定很合理;
但是,也确实给分布式(面向服务、混搭等等本周提到的概念)Web开发带来了麻烦。

  • 本地代理:
    需要一些硬件设施(没有服务器的客户端无法运行),并且带宽和潜伏时间也要加倍(远程服务器-代理服务器-客户端)。

  • Flash:
    远程主机中需要部署一个crossdomain.xml文件,而且,Flash作为一门专有技术,其前途尚不明朗;换句话说,开发人员很可能要学习一种目标不确定的编程语言。

  • Script标签:
    无法确切知道内容是否有效,没有标准的实现方法,又可能被认为是一种“安全风险”。

原理—jsonp的通俗讲解

  • 使用script 的src属性没有同源限制,跨域名获取数据的一种方法

案例—使用script的src获取跨域数据

<script type="text/javascript">
	// 定义一个jp函数
	function jp(data) {
		console.log(data);
	}
</script>
<!-- 使用script 的src属性没有同源限制,跨域名获取数据的一种方法 -->
												<!-- 获取qq.com的天气信息,callback是返回的数据,jp是返回数据后调用的方法 -->
<script src="https://apis.map.qq.com/ws/location/v1/ip?callback=jp&key=CAABZ-AVSAQ-RDR5L-GTBDJ-HLA4O-A5FDB&output=jsonp" ></script>

封装Jsonp

  • 原理:
  • 使用script 的src属性没有同源限制,跨域名获取数据的一种方法
  • 动态的创建script标签,使用src属性来进行跨域获取数据
  • 其中使用有Promise,异步

// jsonp 利用script的src属性没有同源限制,跨域名获取数据的一种方法
// 后端返回的数据格式是,方法名(数据)
// url 最重要 callback名称 jp 是callback的值
function jsonp(url,option={}) {
	// 默认回调函数参数名 callback
	var jp = option.jp||"callback"; 
	// 默认回调函数参数值
	var callback = option.callback||"jp";
	
	return new Promise((resolve,reject) => {
		// 查看url是否有jp 没有还要加上
		if(url.indexOf(jp)==-1){
			url += "&"+jp+"="+callback;
		}
		// 如果有获取这已经加上了callback=值,获取callback的值
		var p1 = url.indexOf(option.jp);	// 获取到callback的位置
		var p2 = url.indexOf("&",p1);	// 从p1的位置开始查找符号"&"
		// 如果查找不到设置的p2位置,
		p2 == -1 ? p2 = url.lenght;
		// 就在url的末尾加,
		callback = url.slice(p1+jp.length+1,p2);
		
		// 动态的创建callback方法
		window[callback]=function(data){ 	
			// 删除
			document.head.removeChild(script);
			resolve(data);					 
		}
		
		// 动态创建script标签
		let script = document.createElement("script");
		// 将需要获取的数据的地址赋值给script 中的src属性,跳过浏览器的同源策略
		script.src = url;
		// 将script标签追加到head中
		document.head.append(script);				
		// script加载失败
		script.onerror = function(e){
			// 动态删除script
			document.head.removeChild(script); 
		reject(e)}
	})
}

案例—获取qq.com中的城市信息与天气信息

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
	</head>
	<body>
		<p id="city" ></p>
		<img src=""  id="img" alt="">
		<p id="weather"></p>
	</body>
	<script type="text/javascript">
		// jsonp 利用script的src属性没有同源限制,跨域名获取数据的一种方法
		// 后端返回的数据格式是,方法名(数据)
		// url 最重要 callback名称 jp 是callback的值
		function jsonp(url,option={}) {
			// 默认回调函数参数名 callback
			var jp = option.jp||"callback"; 
			// 默认回调函数参数值
			var callback = option.callback||"jp";
			
			return new Promise((resolve,reject) => {
				// 查看url是否有jp 没有还要加上
				if(url.indexOf(jp)==-1){
					url += "&"+jp+"="+callback;
				}
				// 如果有获取这已经加上了callback=值,获取callback的值
				var p1 = url.indexOf(jp);	// 获取到callback的位置
				var p2 = url.indexOf("&",p1);	// 从p1的位置开始查找符号"&"
				// 如果查找不到设置的p2位置,
				p2 == -1 ? p2 = url.lenght : '';
				// 就在url的末尾加,
				callback = url.slice(p1+jp.length+1,p2);
				
				// 动态的创建callback方法
				window[callback]=function(data){ 	
					// 删除
					document.head.removeChild(script);
					resolve(data);					 
				}
				
				// 动态创建script标签
				let script = document.createElement("script");
				// 将需要获取的数据的地址赋值给script 中的src属性,跳过浏览器的同源策略
				script.src = url;
				// 将script标签追加到head中
				document.head.append(script);				
				// script加载失败
				script.onerror = function(e){
					// 动态删除script
					document.head.removeChild(script); 
					reject(e)
				}
			})
		}
		
		
		 var url1 = "https://apis.map.qq.com/ws/location/v1/ip?key=CAABZ-AVSAQ-RDR5L-GTBDJ-HLA4O-A5FDB&output=jsonp";
		 var url2 = "https://wis.qq.com/weather/common?weather_type=observe|forecast_24h|air&source=pc&callback=jp";
		 // 获取地址
		 jsonp(url1)
		 .then(res=>{
			 url2 = url2+`&province=${res.result.ad_info.province}&city=${res.result.ad_info.city}`;
			 city.innerHTML=res.result.ad_info.city;
			 return jsonp(url2); //获取天气
		 })
		 .then(res=>{
			 weather.innerHTML=res.data.observe.degree+"℃";
			 // 动态的天气图片
			 img.src="https://mat1.gtimg.com/pingjs/ext2020/qqindex2018/dist/img/weather/"+res.data.observe.weather_code+".svg";
		 })
		
	</script>
</html>

猜你喜欢

转载自blog.csdn.net/qq_34182705/article/details/107056067