(六)AJAX之JSONP跨域

【前言】
  • 本节讲解下利用JSONP实现百度智能搜索案例
  • 需求:
    输入框输入关键字同时,会利用AJAX不断跟后台进行交互,进而实现局部更新页面关键词功能,因为涉及跨域,所以这里用JSONP方式解决
  • 接口URL:
    https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/?wd=&cb=
  • 因为百度搜索接口不太稳定,接下来改用电商接口
  1. 淘宝商品搜索建议http://suggest.taobao.com/sug?code=utf-8&q=商品关键字&callback=cb
  2. PS:callback是回调函数设定

JSONP跨域案例

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<style type="text/css">
			#search{
				width: 630px;
				height: 40px;
				border: 1px solid gray;
				margin: 30px auto;
				display: flex;
				font-size: 18px;
				position: relative;
			}
			#search input{
				width: 80%;
				height: inherit;
				border: none;
				outline: none;
				box-sizing: border-box;
				text-indent: 10px;
			}
			#search button{
				width: 20%;
				height: inherit;
				border: none;
				outline: none;
				box-sizing: border-box;
				background-color: #3385ff;
				color: #fff;
				cursor: pointer;
			}
			#search button:hover{
				background-color: #2d78f4;
			}
			#menu{
				position: absolute;
				left: -1px;
				top: 40px;
				width: 506px;
				height: auto;
				border: 1px solid gray;
				margin: 0;
				box-sizing: border-box;
				padding: 10px;
			}
			#menu li{
				list-style: none;
				box-sizing: border-box;
			}
			#menu li a{
				text-decoration: none;
				color: #333;
				line-height: 20px;
				display: block;
				width: 100%;
				height: 100%;
			}
			#menu li a:hover{
				background-color: rgba(0,0,0,0.2);
			}
		</style>
	</head>
	<body>
		<!-- 第一步.首先编写模板代码,设置静态样式 -->
		<div id="search">
			<input type="text" name="" id="" value="" />
			<button type="button">百度一下</button>
			<!-- 第五步:动态创建元素,创建关键词智能匹配列表 -->
			<ul id="menu"></ul>
		</div>
		<script type="text/javascript">
			/* 第二步.编写键盘事件,监听按键松开,获取输入值 */
			/* 百度一下 */
			var searchText = document.querySelector("#search");
			/* 键盘事件 */
			searchText.addEventListener("keyup",function(){
				/* 第四步:script标签筛选去重
				日常使用时,只需要创建一个script标签即可,后期修改关键字时,只需要修改src就行了。
				所以接下来判断下script标签是否重复,做判断处理。 */
				if(document.querySelector("#new_script_id")){
					document.querySelector("#new_script_id").remove();
				}
				/* 第三步.动态创建script标签,利用JSONP原理跨域调取数据
				获取到输入值之后,需要动态写入内容。接下来使用JSONP跨域,所以需要动态创建script标签。
				接口:https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/?wd=&cb=
				关键字为wd,回调函数为cb,所以对代码封装如下 */
				var wd = this.childNodes[1].value;/* ①关键词 */
				var new_script = document.createElement('script');/* ②动态创建script标签 */
				new_script.id = "new_script_id";/* 设置id */
				// console.log(wd);
				// new_script.src = "https://suggest.taobao.com/sug?code=utf-8&q=" + wd + "&callback=cb";/* ③拼接 */
				new_script.src = "http://suggest.taobao.com/sug?code=utf-8&q="+ wd +"&callback=cb";
				document.body.appendChild(new_script);
				
			},false);			
			/* ④回调函数 */
			/* 第五步:动态创建元素,创建关键词智能匹配列表 */
			var menu = document.querySelector("#menu");
			function cb(option){
				var str = "";
				for(var i=0;i<option.result.length;i++){
					// str += "<li><a href=''>" + option.result[i][0] + "</a></li>";
					/* 第六步:添加跳转事件
					 目前为止,点击智能搜索列表项,无法完成跳页,此时需要另外一个搜索接口http://suggest.taobao.com/sug?code=utf-8&q=*/
					str += "<li><a href='http://suggest.taobao.com/sug?code=utf-8&q=" + option.result[i][0] + "'>" + option.result[i][0] + "</a></li>";
					console.log(option.result[i][0]);
				}
				menu.innerHTML = str;
				
				
			}
			
		</script>
	</body>
</html>

在这里插入图片描述

JSONP限制

优点:

  1. 它不像XMLHttpRequest对象实现的Ajax请求那样受到同源策略的限制,JSONP可以跨越同源策略
  2. 兼容性更好,在更加古老的浏览器中都可以运行,不需要XMLHttpRequest或ActiveX的支持
  3. 在请求完毕后可以通过调用callback的方式回传结果。将回调方法的权限给了调用方,相当于将controller层和view层分开。提供的jsonp服务只提供纯服务的数据,至于提供服务以 后的页面渲染和后续view操作都由调用者来自己定义。如果有两个页面需要渲染同一份数据,只需要有不同的渲染逻辑就可以了,逻辑都可以使用同 一个jsonp服务。

JSONP优缺点

缺点:

  1. 请求类型:它只支持GET请求而不支持POST等其它类型的HTTP请求
  2. 不能解决不同域的两个页面之间如何进行JavaScript调用的问题
  3. 响应状态:jsonp在调用失败的时候不会返回各种HTTP状态码
  4. 安全性:最大缺点是安全性,假如提供jsonp的服务存在页面注入漏洞,即它返回的javascript的内容被人控制的。那么结果是什么?所有调用这个 jsonp的网站都会存在漏洞。于是无法把危险控制在一个域名下…所以在使用jsonp的时候必须要保证使用的jsonp服务必须是安全可信的。

跨域

前言:

  • 浏览器出于安全的考量(避免恶意网站轻易读取其他网站显示的内容,因为该内容可能含有敏感信息,想象iframe嵌套银行网页)原则上允许跨域写而限制了跨域读。写是指数据的上行/发送(sending request),读是指数据的下行/接收(receiving response)。
  • 然而跨域写也是很不安全的,容易导致CSRF/clickjacking攻击。浏览器已经限制了跨域读,再限制跨域写的话,那互联网的每个页面都成了孤岛。避免非法跨域写需要用到token。

考虑下述情况:

  1. 指向外部域名的link和通过表单的向外部域发起get请求是一样的,也都是允许的,点击那一刻起,浏览器的当前域名转向了目标网站,也就完全是域内读了。
  2. 通过表单向外部域发起post请求也是允许的,理由同上,源网站无法读取目标网站的任何内容。
  3. AJAX(借助XMLHttpRequest对象)跨域get/post是禁止的,因为使用AJAX就是为了读取响应的内容,这触碰了跨域读的限制。
  4. JSONP属于跨域读,且形式限制为get请求,因为它利用了script标签的特性(浏览器认为跨域读脚本是例外,类似的还有img、iframe等等,注意它们共有的src属性)。
因此对于浏览器而言:1和2没有跨域;3遵循了限制跨域读的原则;4属于允许的例外。

分析:

  • 虽然JSONP很好用,但它注定是get请求,get请求有语义要求(幂等)、长度限制(为了兼容限制255字节)、安全隐患(容易受到csrf攻击,csrf的解决必须是post请求配合token使用)
  • 扫盲:CSRF(Cross-site request forgery)跨站请求伪造,通常缩写为CSRF或者XSRF,是一种对网站的恶意利用。

post跨域

跨域post请求:

1、CORS(跨域资源共享)
2、invisible iframe(隐形)
3、server proxy (服务器代理权)
4、flash proxy(flash 代理权)

1、CORS跨域资源共享

  • 概述:Cross-Origin Resource Sharing,W3C制定的跨站资源分享标准。
  • 优点:W3C标准方案
  • 缺点:不兼容老浏览器
  • 注意:若在多个iframe之间跨域通信,优先考虑 window.postMessage(H5 新技术→ 安全地实现Window对象之间的跨域通信)

2、invisible iframe(隐形)

  • 概述:通过js动态生成不可见表单和iframe,将表单的target设为iframe的name以此通过iframe做post提交。提交后由于跨域,无法直接读取响应内容。一般的做法是,iframe内通过js改变自身location的fragment,外部则监听iframe的onload事件,读取fragment的内容。有现成的跨域iframe通信类库,如jQuery PostMessage Plugin。
  • 优点:兼容性佳,facebook,google,新浪已/曾采用
  • 缺点:依赖hack实现,响应数据量大时需要切片、多次设置fragment并轮询,响应频繁时可能失效

3、server proxy (服务器代理权)

  • 概述:当前域实现一个代理,所有向外部域名发送的请求都径由该代理中转。
  • 缺点:每个使用方都需要部署代理,数据中转低效,对js有侵入。

4、flash proxy(flash 代理权)

  • 概述:利用不可见的swf跨域post提交数据,需要部署crossdomain.xml。例如alirte会自动检测,若用户安装了flash,则以此实现跨域通信。
  • 要求:flash9,缺点:依赖flash
  • 优点:ADOBE标准方案,相对CORS兼容性佳,相对invisible iframe响应数据量较大时优势明显。

JSONP跨域

手机查询接口

http://tcc.taobao.com/cc/json/mobile_tel_segment.htm?tel=手机号

案例:

在这里插入图片描述

步骤分析:

  1. 编写静态页面
  2. 绑定监听事件,获取输入值
  3. 调用手机信息查询接口并调用回调函数
  4. 定义回调函数,检测返回数据
  5. 解析数据,js操作返回数据,实现页面局部刷新
		<input type="tel" name="" id="" value="" />
		<button type="button" name="searchPhone">查询</button>
		<script type="text/javascript">
			/* ③声明回调函数 */
			function handleRespone(option){
				console.log(option);
			}
			/* 事件监听 */
			var tel = document.querySelector("input[type='tel']");
			var searchPhoneBtn = document.querySelector("button[name='searchPhone']");
			searchPhoneBtn.addEventListener("click",function(){
				var mobile = tel.value;
				console.log(mobile)
				var script = document.createElement("script");
				/* ①传参    ②回调函数 */
				script.src = "http://tcc.taobao.com/cc/json/mobile_tel_segment.htm?tel"+mobile+"&callback=handleRespone";
				document.getElementsByTagName("head")[0].appendChild(script);
			},false)
		</script>

JSONP步骤小结

  1. 动态创建
				var script = document.createElement("script");
				script.src = "http://tcc.taobao.com/cc/json/mobile_tel_segment.htm?tel"+mobile+"&callback=handleRespone";
				document.getElementsByTagName("head")[0].appendChild(script);
  1. 在页面中,返回的JSON作为参数传入回调函数中,然后通过回调函数来来操作数据,最后在控制台,可以查看到返回的response数据格式为JSON对象格式的,具体需要取出哪些参数,可以根据自己的需要
/* ③声明回调函数 */
			function handleRespone(option){
				console.log(option);
			}

以上为开发中的步骤,但从原理角度出发,正确解析步骤应该为

  1. 首先在客户端注册一个callback,然后把callback的名字传给服务器
  2. 客户端浏览器,解析script标签,并执行返回的 javascript 文档
    在这里插入图片描述

JSONP小结

(一) JSONP实现跨域请求的原理

简单的说,就是动态创建

(二)JSONP构成部分

两部分组成:回调函数和数据。回调函数是当响应到来时应该在页面中调用的函数。回调函数的名字一般是在请求中指定的。而数据就是传入回调函数中的 JSON 数据。

(三)JSONP安全性

JSONP 是从其他域中加载代码执行。如果其他域不安全,很可能会在响应中夹带一些恶意代码,而此时除了完全放弃 JSONP 调用之外,没有办法追究。因此在使用别人的Web 服务时,一定得保证它安全可靠。

(四)JSONP请求类型

JSONP只支持get请求类型,不支持post请求。原理是使用script标签进行的,标签默认就是get请求,标签没有位置让你设置post。

JSONP跨域局限

JSONP解决跨域虽然是常用的方法,但也存在很多局限
  1. 不能接受HTTP状态码
  2. 不能使用POST提交(默认GET)
  3. 不能发送和接受HTTP头
  4. 不能设置同步调用(默认异步)

其最严重的就是不能提供错误处理,如果请求的代码正常执行那么会得到正确的结果。如果请求失败,如404,500之类,那么可能什么都不会发生。即要确定 JSONP 请求是否失败很难,虽然 HTML5 给

JSONP跨域小结

  • 总结出来就一句话,如果你要使用jsonp,一定要知道并接受它的缺点,因为你只能适应它
  • 但在日常开发里,最好的方式就是尽量不要使用jsonp,跨域这块交给后端来解决,那样前端就可以使用一些axios、fetch、http等框架来发送请求,这样就能正常的拿到你想要的状态码。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值