前端工程化17-邂逅原生的ajax、跨域、JSONP

5、邂逅原生的ajax

5.1、什么是ajax

AJAX 全称为Asynchronous Javascript And XML,就是异步的 JS 和 XML。通过AJAX可以在浏览器中向服务器发送异步请求,最大的优势:页面无刷新获取数据。AJAX 不是新的编程语言,而是一种将现有的标准组合在一起使用的新方式。

5.2、XML简介

XML 可扩展标记语言。

XML 被设计用来传输和存储数据。

XML和HTML类似,不同的是HTML中都是预定义标签,而XML中没有预定义标签,全都是自定义标签,用来表示一些数据。

用XML表示一个学生数据:

xml 复制代码
<student>
        <name>孙悟空</name>
        <age>18</age>
        <gender>男</gender>
</student>

现在已经被JSON取代了。

json 复制代码
{"name":"孙悟空","age":18,"gender":"男"}

但是还有一些老系统在用这种数据交换格式,因为替换的成本实在太大,不能接受

5.3、ajax的优点

可以无需刷新页面而与服务器端进行通信。

允许你根据用户事件来更新部分页面内容。

5.4、AJAX的缺点

没有浏览历史,不能回退;固有问题

存在跨域问题;可以解决

SEO不友好; 没有意义,有竞价排名这个东西

5.5、AJAX核心对象

XMLHttpRequest,AJAX的所有操作都是通过该对象进行的。

函数、函数对象、方法

5.6、搭建测试ajax请求的服务器

创建项目(变成一个符合npm规范的包)

​ npm init

​ yarn inti

规定项目名称(不能有大写字母,也不能有数字开头)

​ ajax_0826

​ 一路回车

安装express

​ yarn add express

新建一个server.js文件

​ 下带附件

启动服务器

​ node server.js

​ 右键 Code Runner插件

​ 推荐敲命令,后期我们脚手架里都是敲命令

热启动node服务

​ nodemon server.js

服务器附件文件

js 复制代码
//引入express
const express = require('express')
const cors = require('cors')

//创建app实例对象
const app = express()
//使用中间件解析urlencoded编码形式的请求体参数
app.use(express.urlencoded({extended:true}))
//使用中间件解析json编码形式的请求体参数
app.use(express.json())
app.use(cors())

//暴露静态资源
app.use(express.static(__dirname+'/src'))

//响应GET请求--可以接收query参数
app.get('/test_get',(request,response)=>{
	console.log('有人请求test_get了--携带的query参数是:',request.query);
	/* response.setHeader('Access-Control-Allow-Origin','*')
	response.setHeader('Access-Control-Expose-Headers','*') */
	response.send('hello_test_get')
})

//响应GET请求--可以接收params参数
app.get('/test_get2/:name/:age',(request,response)=>{
	console.log('有人请求test_get2了--携带的params参数是:',request.params);
	response.send('hello_test_get2')
})

//响应get请求
app.get('/get_person',(request,response)=>{
	console.log('有人请求get_person了');
	const person = {name:'tom',age:18,sex:'女'}
	response.send(JSON.stringify(person))
})

//响应get请求
app.get('/get_person_delay',(request,response)=>{
	console.log('有人请求get_person了');
	const person = {name:'tom',age:18,sex:'女'}
	setTimeout(()=>{
		response.send(JSON.stringify(person))
	},3000)
})

//响应POST请求--可以接收请求体参数
app.post('/test_post',(request,response)=>{
	console.log('有人请求test_post了--携带的请求体参数是',request.body);
	response.send('hello_test_post')
})

//响应get请求---jquery
app.get('/test_jquery_get',(request,response)=>{
	console.log('有人请求test_jquery_get了',request.query);
	const car = {name:'马自达·阿特兹',price:'25万'}
	response.send(JSON.stringify(car))
})

//响应post请求----jquery
app.post('/test_jquery_post',(request,response)=>{
	console.log('有人请求test_jquery_post了',request.body);
	const car = {name:'马自达·阿特兹',price:'25万'}
	response.send(JSON.stringify(car))
})

/* app.options('/test_put',(request,response)=>{
	response.setHeader('Access-Control-Allow-Origin','*')
	response.setHeader('Access-Control-Expose-Headers','*')
	response.setHeader('Access-Control-Allow-Methods','*')
	response.send()
}) */

app.put('/test_put',(request,response)=>{
/* 	response.setHeader('Access-Control-Allow-Origin','*')
	response.setHeader('Access-Control-Expose-Headers','*') */
	response.send('hello_test_put')
})

app.get('/test_jsonp',(request,response)=>{
	const {callback} = request.query
	console.log(callback);
	const person = [{name:'tom',age:18},{name:'老刘',age:5}]
	response.send(`${callback}(${JSON.stringify(person)})`)
})

//监听
app.listen(8080,(err)=>{
	if(!err) {
		console.log('测试ajax请求的服务器开启成功了!测试地址如下');
		console.log('http://127.0.0.1:8080/1_ajax小试牛刀.html');
		console.log('http://127.0.0.1:8080/2_xhr的5种状态.html');
		console.log('http://127.0.0.1:8080/3_ajax_get请求.html');
		console.log('http://127.0.0.1:8080/4_ajax_post请求.html');
		console.log('http://127.0.0.1:8080/5_ajax_解析json数据.html');
		console.log('http://127.0.0.1:8080/6_ajax_处理IE浏览器get请求缓存问题.html');
		console.log('http://127.0.0.1:8080/7_ajax请求的异常与超时处理.html');
		console.log('http://127.0.0.1:8080/8_ajax取消请求.html');
		console.log('http://127.0.0.1:8080/9_避免多次重复请求.html');
		console.log('http://127.0.0.1:8080/10_jquery封装的ajax.html');
		console.log('http://127.0.0.1:8080/11_演示回调地狱.html');
	}
})

5.6、如何使用AJAX的核心对象

javascript 复制代码
//1.创建XMLHttpRequest实例对象
const xhr = new XMLHttpRequest()
//2.设置请求信息
xhr.open(method,url) //配置请求
xhr.setRequestHeader(key,value)//设置请求头(可选)
//3.发送请求
xhr.send(body) //get请求不传body参数,只有post请求使用
//4.接收响应
xhr.onreadystatechange = ()=>{
    if(xhr.readyState === 4 && xhr.status === 200 ){
            			console.log(xhr.response)
    }
}

5.7、解决IE缓存问题

问题:在一些浏览器中(IE),由于缓存机制的存在,ajax只会发送的第一次请求,剩余多次请求不会在发送给浏览器而是直接加载缓存中的数据。

解决方式:浏览器的ajax缓存是根据url地址来记录的,所以我们只需要修改url地址即可避免缓存问题

js 复制代码
xhr.open('get','url/t='+Date.now())
html 复制代码
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>6_ajax_处理IE-get请求缓存问题</title>
		<style>
			#content{
				width: 300px;
				height: 100px;
				border: 1px solid black;
				margin-top: 10px;
			}
		</style>
	</head>
	<body>
		<h3>该页面是测试:ajax_处理IE-get请求缓存问题</h3>
		<button id="btn">点我发送请求(原生js-ajax-get)</button>
		<div id="content"></div>
		<script type="text/javascript" >
			const btn = document.getElementById('btn')
			const content = document.getElementById('content')

			btn.onclick = function(){
				//实例xhr
				const xhr = new XMLHttpRequest()

				//绑定监听
				xhr.onreadystatechange = function(){
					if(xhr.readyState === 4){
						if(xhr.status >= 200 && xhr.status <300){
							console.log(xhr.response);
						}
					}
				}
				
				//配置请求
				xhr.open('GET','http://127.0.0.1:8080/get_person?t='+Date.now())

				//responseType用于指定返回数据的格式
				xhr.responseType = 'json'

				//发送请求
				xhr.send()
			}
		</script>
	</body>
</html>

强缓存、协商缓存

浏览器禁用缓存 Disable cache

按住shift,点刷新,或者shift+f5,强制刷新后,点击获取数据。发现数据http请求状态码为304,证明本次请求走了协商缓存

关闭浏览器,关闭服务器,从新打开浏览器服务器

第一次请求状态码为200,数据成功回来,第二次请求状态码为200,第三次状态码为304,这是因为浏览器发现地址栏信息并没有发送对应的改变,,他会去问下服务器,你的数据是否发生了变化,服务器发现没变,给个304 你小子走协商缓存就好了,协商缓存终归还是给服务器发送了请求

IE这个东西就非常的武断,地址没变直接就会走缓存

5.8、AJAX请求状态

xhr.readyState 可以用来查看请求当前的状态

  • 0: 表示XMLHttpRequest实例已经生成,但open未调用。

  • 1: open已调用,但send还未调用,此时仍然可以修改请求头信息。

  • 2: 表示send()方法已经执行,并且头信息和状态码已经收到。

  • 3: 表示正在接收服务器传来的部分数据。

  • 4:表示数据已经接收完毕

5.9、原生AJAX小试牛刀

html 复制代码
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>1_ajax小试牛刀</title>
		<style>
			#content{
				width: 300px;
				height: 100px;
				border: 1px solid black;
				margin-top: 10px;
			}
		</style>
	</head>
	<body>
		<h3>该页面是测试:ajax小试牛刀</h3>
		<button id="btn">点我发送请求(原生js-ajax-get)</button>
		<div id="content"></div>
		<script type="text/javascript" >
			//获取按钮
			const btn = document.getElementById('btn')
			const content = document.getElementById('content')
			//给按钮绑定监听
			btn.onclick = ()=>{
				//1.创建xhr实例对象
				const xhr = new XMLHttpRequest()

				//on  当xxx时候
				//ready 准备
				//state 状态
				//change 状态
				//xhr内部有5种状态,值分别为:0、1、2、3、4
				//xhr实例对象,在实例出来的那一刻状态就是0
				xhr.onreadystatechange = ()=>{
					if(xhr.readyState === 4){
						console.log(xhr.response);
						content.innerHTML = `<h3>${xhr.response}</h3>`
					}
				}

				//2.指定发送请求的:method、url
				xhr.open('GET','http://127.0.0.1:8080/test_get')
				
				//3.发送请求
				xhr.send()
			}
		</script>
	</body>
</html>

5.1、xhr的5种状态

html 复制代码
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>2_xhr的5种状态</title>
		<style>
			#content{
				width: 300px;
				height: 100px;
				border: 1px solid black;
				margin-top: 10px;
			}
		</style>
	</head>
	<body>
		<h3>该页面是测试:xhr的5种状态</h3>
		<button id="btn">点我发送请求(原生js-ajax-get)</button>
		<div id="content"></div>
		<script type="text/javascript" >
			//获取按钮
			const btn = document.getElementById('btn')
			const content = document.getElementById('content')
			//给按钮绑定监听
			btn.onclick = ()=>{
				//1.创建xhr实例对象
				const xhr = new XMLHttpRequest()

				//xhr实例对象,在实例出来的那一刻状态就是0
				/* 
					xhr内部有5种状态,值分别为:0、1、2、3、4
							0:实例出来的那一刻状态就是0,初始状态。
							1:open已经调用了,但是send还没有调用,此时可以修改请求头内容。
							2:send已经调用了,已经无法修改请求头
							3:已经回来一部分数据了,小的数据会在此阶段一次性接收完毕,较大的数据有待进一步接收,响应头回来了。
							4:数据全部接收完毕
				*/
				xhr.onreadystatechange = ()=>{
					/* if(xhr.readyState === 1){
						xhr.setRequestHeader('demo',123) //配置请求头
					} */
					/* if(xhr.readyState === 2){
						xhr.setRequestHeader('demo',123) //配置请求头--报错
					} */
					if(xhr.readyState === 3){
						console.log('3时接收到的数据',xhr.response);
						console.log('3时接收到的响应头',xhr.getAllResponseHeaders());
					}
					if(xhr.readyState === 4 && (xhr.status >= 200 && xhr.status < 300)){
						console.log(xhr.response);
						content.innerHTML = `<h3>${xhr.response}</h3>`
					}
				}

				//2.指定发送请求的:method、url
				xhr.open('GET','http://127.0.0.1:8080/test_get')
				
				//3.发送请求
				xhr.send()
			}
		</script>
	</body>
</html>

5.2、ajax的get请求

html 复制代码
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>3_ajax_get请求</title>
		<style>
			#content{
				width: 300px;
				height: 100px;
				border: 1px solid black;
				margin-top: 10px;
			}
		</style>
	</head>
	<body>
		<h3>该页面是测试:ajax_get请求</h3>
		<button id="btn">点我发送请求(原生js-ajax-get)</button>
		<div id="content"></div>
		<script type="text/javascript" >
			//获取按钮
			const btn = document.getElementById('btn')
			const content = document.getElementById('content')
			//给按钮绑定监听
			btn.onclick = ()=>{
				//1.创建xhr实例对象
				const xhr = new XMLHttpRequest()

				//绑定监听
				xhr.onreadystatechange = ()=>{
					if(xhr.readyState === 4 ){
						if(xhr.status >= 200 && xhr.status < 300){
							console.log(xhr.response);
							content.innerHTML = `<h3>${xhr.response}</h3>`
						}
					}
				}

				//#region 
				/* 
						1.形如:key=value&key=value 就是query参数的urlencoded编码形式
						2.形如:/xx/xxx/老刘/18 就是params参数
				*/
				//#endregion
				//2.指定发送请求的:method、url、参数
				// xhr.open('GET','http://127.0.0.1:8080/test_get?name=老刘&age=18') //携带query参数
				xhr.open('PUT','http://127.0.0.1:8080/test_put') //携带params参数
				
				//3.发送请求
				xhr.send()
			}
			 
		</script>
	</body>
	<!-- 
	  get请求 
	    1、query参数
			 key=value&key=value 就是query参数的urlencoded编码形式
	    2、params参数 
	 		 /xx/xxx/老刘/18 就是params参数 
			 	这里有个小疑问?
				都是路径上的拼接我怎么知道他是地址的拼接还是参数一般来说在服务器有特殊的写法
				例如node服务器后端接口的写法/getList/:name/:age.
				例如SpringBoot后端接口的写法@PathVariable("name") String name
				在vue路由传参的写法上也有对应的params传参例如 {path: '/search/:words', component: Search} 他是有点类似于node服务器的写法	
		3、vscode折叠
			 #region							
	-->
</html>

5.3、ajax的post请求

html 复制代码
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>4_ajax_post请求</title>
		<style>
			#content{
				width: 300px;
				height: 100px;
				border: 1px solid black;
				margin-top: 10px;
			}
		</style>
	</head>
	<body>
		<h3>该页面是测试:ajax_post请求</h3>
		<button id="btn">点我发送请求(原生js-ajax-post)</button>
		<div id="content"></div>
		<script type="text/javascript" >
			//获取按钮
			const btn = document.getElementById('btn')
			const content = document.getElementById('content')
			//给按钮绑定监听
			btn.onclick = ()=>{
				//1.创建xhr实例对象
				const xhr = new XMLHttpRequest()

				//绑定监听
				xhr.onreadystatechange = ()=>{
					if(xhr.readyState === 4 ){
						if(xhr.status >= 200 && xhr.status < 300){
							console.log(xhr.response);
							content.innerHTML = `<h3>${xhr.response}</h3>`
						}
					}
				}

				//2.指定发送请求的:method、url、参数
				xhr.open('POST','http://127.0.0.1:8080/test_post')

				//追加响应头用于标识携带请求体参数的编码形式--urlencoded
				xhr.setRequestHeader('Content-type','application/x-www-form-urlencoded')

				//追加响应头用于标识携带请求体参数的编码形式--json
				//xhr.setRequestHeader('Content-type','application/json')
				
				//3.发送请求
				const person = {name:'老刘',age:20}

				xhr.send('name=老刘&age=18') //携带urlencoded编码形式的请求体参数
				// xhr.send(JSON.stringify(person)) //携带json编码形式的请求体参数
			}
		</script>
	</body>
</html>
<!-- 
  我们在上一个案例中、介绍到get请求可以携带query 和params参数、那么在post请求中都可以带什么参数呢?
  在我们一般的认知概念中、post请求带的是请求体参数、其实不是的他既可以携带query和parmas,但是一般我们都是放到请求体里
  post请求
	1、query
	2、parmas参数
	3、body参数
		放到send里边就是请求体参数、携带的是urlencoded编码形式的请求体参数
		当然我们也可以携带json编码形式的请求体参数
		注意必须携带请求头
			xhr.setRequestHeader('Content-type','application/x-www-form-urlencoded')
			xhr.setRequestHeader('Content-type','application/json')
	4、题外话	
	    联想我们后端的技术我们发现后端接口在接收数据的时候,有的时候他用了注解有时候没有用,这是因为
		编码形式的不同,一种是urlencoded 一种是json格式的,一般如果前端发送json格式那么我们后端就需要用注解
-->

5.4、复习git操作

接下来我们需要回顾下怎么操作git,在接触Es6之前,我们已经系统的学习过了如何操作git,当你电脑上已经安装git客户端,你可以通过cmd黑窗口进行git操作,windows10操作系统也有一个工具 Windows PowerShell ,也可以通过git客户端自带的两种工具一个是GIT GUI Here、GIT Bash Here,cmd黑窗口的兼容性比较好,因为他从xp那个年代他就存在了,比如看看C盘下都有什么文件,使用命令dir,那我可以在cmd里敲Linux命令嘛?不好意思这是不支持的的,那谁支持呢?windows10的PowerShell是支持的,这个东西最大的优势是原始的Windows的shell脚本支持,Linux的也支持,这个东西我们用的不是很多,因为这个东西有的时候全局安装一个东西他就中断了,他说你没有权限去访问,用的多的还是cmd,GitBashHere就可以理解为一个是一个赠品。都可以,但是最好不要在PowerShell里敲了,有的时候全局安装东西容易出现问题,我那选择的使用方式是另一款软件Open Terminur here,他是一个单独的软件,他的劣势是启动速度比较慢,优势在于非常的美观,可以像浏览器一样开多个标签页,也可以调试那个字体颜色大小。

一般我们新到公司了,人家肯定会给你git地址,我们使用git clone 地址克隆下来,进入到桌面怎么进?桌面叫做Desktop 使用命令 cd des 按下tab他就联想了mkdir test,git clone 克隆一个仓库, 存在一个依赖管理文件,npm的话就是npm i,yarn的话就直接安装所有依赖,接下来就是git pull origin master,拉取写代码,add 添加到暂存区,git commit -m 'update' git push推送代码,在使用git项目管理项目时候,最大问题就是在处理冲突,分支的合并

5.5、VsCode怎么操作git

冲突就是同一行位置上产生了不同的内容就是冲突

更改移动到右边这是不对的,右箭头是还原块的意思,+号箭头是暂存块

左侧工具栏更改旁边有一个+好,可以把所有更改的文件添加到暂存区,跟 git add .效果一样

暂存的更改旁边有一个减号意思是从暂存区域给他撤回来

消息输入框、可以输入对应的提交信息,跟 git -m "提交了一个文件",此时只是我们本地仓库管理了对应文件

在往上走一点有三个点,点击,会显示拉取 推送、克隆、提交、更改、拉取、推送等选项操作

常用的几个命令

clone init add commit push pull

5.6、怎么改VsCode快捷键及代码片段

小齿轮--->键盘快捷方式---->搜索对应的键

ctrl+w 改为向下复制行

小齿轮---->用户代码片段

html.json js.json a.vue

5.7、解析json数据

html 复制代码
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>5_ajax_解析json数据</title>
		<style>
			#content{
				width: 300px;
				height: 100px;
				border: 1px solid black;
				margin-top: 10px;
			}
		</style>
	</head>
	<body>
		<h3>该页面是测试:ajax_解析json数据</h3>
		<button id="btn">点我发送请求(原生js-ajax-get)</button>
		<div id="content"></div>
		<script type="text/javascript" >
			const btn = document.getElementById('btn')
			const content = document.getElementById('content')

			btn.onclick = ()=>{
				//实例xhr
				const xhr = new XMLHttpRequest()

				//绑定监听
				xhr.onreadystatechange = ()=>{
					if(xhr.readyState === 4){
						if(xhr.status >= 200 && xhr.status <300){
							const {name,age,sex} = xhr.response
							content.innerHTML = (`
								<ul>
									<li>姓名:${name}</li>
									<li>年龄:${age}</li>
									<li>性别:${sex}</li>
								<ul>
								`)
						}
					}
				}
				
				//配置请求
				xhr.open('GET','http://127.0.0.1:8080/get_person')

				//responseType用于指定返回数据的格式
				xhr.responseType = 'json'

				//发送请求
				xhr.send()
			}
		</script>
	</body>
</html>

5.8、对象的连续结构赋值

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
     <script type="text/javascript">
         let  obj={a:1,b:{c:2}}
        //  const {c}=obj.b; //标准的解构赋值写法
         console.log(c);

         const {b:{c}}=obj
         console.log(c);//连续的机构赋值 react项目中会有这种写法
         
         //如何让c改个名字,重命名
         const {b:{c:value}}=obj
         console.log(value);

     </script>
</body>
</html>

5.9、ajax请求的异常与超时处理

html 复制代码
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>7_ajax请求的异常与超时处理</title>
		<style>
			#content{
				width: 300px;
				height: 100px;
				border: 1px solid black;
				margin-top: 10px;
			}
		</style>
	</head>
	<body>
		<h3>该页面是测试:ajax请求的异常与超时处理</h3>
		<button id="btn">点我发送请求(原生js-ajax-get)</button>
		<div id="content"></div>
		<script type="text/javascript" >
			const btn = document.getElementById('btn')
			const content = document.getElementById('content')

			btn.onclick = function(){
				//实例xhr
				const xhr = new XMLHttpRequest()

				//绑定监听
				xhr.onreadystatechange = function(){
					if(xhr.readyState === 4){
						if(xhr.status >= 200 && xhr.status <300){
							const {name,age,sex} = xhr.response
							content.innerHTML = (`
								<ul>
									<li>姓名:${name}</li>
									<li>年龄:${age}</li>
									<li>性别:${sex}</li>
								<ul>
								`)
						}
					}
				}
				
				//配置请求
				xhr.open('GET','http://127.0.0.1:8080/get_person_delay')

				//responseType用于指定返回数据的格式
				xhr.responseType = 'json'

				//配置出错的回调
				xhr.onerror = ()=>{
					alert('当前网络不稳定,请稍后重试');
				}

				//超时时间
				xhr.timeout = 2000 

				//超时的回调
				xhr.ontimeout = ()=>{
					alert('网速不给力,请切换网络重试');
				}

				//发送请求
				xhr.send()
			}
		</script>
	</body>
</html>

6.0、取消请求

html 复制代码
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>8_ajax取消请求</title>
		<style>
			#content{
				width: 300px;
				height: 100px;
				border: 1px solid black;
				margin-top: 10px;
			}
		</style>
	</head>
	<body>
		<h3>该页面是测试:ajax取消请求</h3>
		<button id="btn">点我发送请求(原生js-ajax-get)</button>
		<button id="btn2">取消请求</button>
		<div id="content"></div>
		<script type="text/javascript" >
			const btn = document.getElementById('btn')
			const btn2 = document.getElementById('btn2')
			const content = document.getElementById('content')
			let xhr 

			btn.onclick = ()=>{
				//实例xhr
				xhr = new XMLHttpRequest()

				//绑定监听
				xhr.onreadystatechange = function(){
					if(xhr.readyState === 4){
						if(xhr.status >= 200 && xhr.status <300){
							const {name,age,sex} = xhr.response
							content.innerHTML = (`
								<ul>
									<li>姓名:${name}</li>
									<li>年龄:${age}</li>
									<li>性别:${sex}</li>
								<ul>
								`)
						}
					}
				}
				
				//配置请求
				xhr.open('GET','http://127.0.0.1:8080/get_person_delay')

				//responseType用于指定返回数据的格式
				xhr.responseType = 'json'

				//配置出错的回调
				xhr.onerror = ()=>{
					alert('当前网络不稳定,请稍后重试');
				}

				//超时时间
				xhr.timeout = 2000 

				//超时的回调
				xhr.ontimeout = ()=>{
					alert('网速不给力,请切换网络重试');
				}

				//发送请求
				xhr.send()
			}
			
			btn2.onclick = ()=>{
				xhr.abort()
			}
		</script>
	</body>
</html>

5.1、避免重复发送请求

html 复制代码
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>9_避免多次重复请求</title>
		<style>
			#content{
				width: 300px;
				height: 100px;
				border: 1px solid black;
				margin-top: 10px;
			}
		</style>
	</head>
	<body>
		<h3>该页面是测试:避免多次重复请求</h3>
		<button id="btn">点我发送请求(原生js-ajax-get)</button>
		<div id="content"></div>
		<script type="text/javascript" >
			const btn = document.getElementById('btn')
			const content = document.getElementById('content')
			let xhr 
			let isLoading

			btn.onclick = ()=>{
				if(isLoading) xhr.abort()
				
				//实例xhr
				xhr = new XMLHttpRequest()

				//绑定监听
				xhr.onreadystatechange = function(){
					if(xhr.readyState === 4){
						if(xhr.status >= 200 && xhr.status <300){
							isLoading = false
							const {name,age,sex} = xhr.response
							content.innerHTML = (`
								<ul>
									<li>姓名:${name}</li>
									<li>年龄:${age}</li>
									<li>性别:${sex}</li>
								<ul>
								`)
						}
					}
				}
				
				//配置请求
				xhr.open('GET','http://127.0.0.1:8080/get_person_delay')

				//responseType用于指定返回数据的格式
				xhr.responseType = 'json'

				//发送请求
				xhr.send()
				isLoading = true
			}
			
		</script>
	</body>
</html>

在绝对快的情况下,也不能保证发送的绝对是一次请求,但是防止大量的重复点击足够了、我们要优化就让这个按钮不能重复点击就好了

isLoading = false 提升下这个放置位置

5.2、测试Jquery封装的ajax

html 复制代码
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>10_jQuery封装的ajax</title>
		<style>
			#content{
				width: 300px;
				height: 100px;
				border: 1px solid black;
				margin-top: 10px;
			}
		</style>
		<script type="text/javascript" src="./js/jquery.min.js"></script>
	</head>
	<body>
		<h3>该页面是测试:jQuery封装的ajax</h3>
		<button id="btn1">点我发送请求(jQuery-ajax-get)</button>
		<button id="btn2">点我发送请求(jQuery-ajax-post)</button>
		<div id="content"></div>
		<script type="text/javascript" >
			const btn1 = $('#btn1')
			const btn2 = $('#btn2')
			const content = $('#content')

			btn1.click(()=>{
				//使用jQuery发送ajax-get(完整版)
				$.ajax({
					url:'http://127.0.0.1:8080/test_jquery_get', //请求地址
					method:'GET',//请求方式(默认值是GET)
					data:{school:'atguigu'},//携带的数据
					dataType:'json',//配置响应数据格式
					timeout:2000,//指定超时的时间
					success:(result,reponseText,xhr)=>{
						console.log(result,reponseText,xhr);
						content.append(`<div>汽车名:${result.name},价格:${result.price}</div>`)
					},//成功的回调
					error:(xhr)=>{console.log('请求出错了',xhr);} //失败的回调
				})

				//使用jQuery发送ajax-get(精简版)
				/* $.get('http://127.0.0.1:8080/test_jquery_get',{school:'atguigu'},(data)=>{
					console.log(data);
					content.append(`<div>汽车名:${data.name},价格:${data.price}</div>`)
				},'json') */
			})

			btn2.click(()=>{
				//使用jQuery发送ajax-post(完整版)
				$.ajax({
					url:'http://127.0.0.1:8080/test_jquery_post', //请求地址
					method:'POST',//请求方式(默认值是GET)
					data:{school:'atguigu'},//携带的数据
					dataType:'json',//配置响应数据格式
					timeout:2000,//指定超时的时间
					success:(result,reponseText,xhr)=>{
						console.log(result,reponseText,xhr);
						content.append(`<div>汽车名:${result.name},价格:${result.price}</div>`)
					},//成功的回调
					error:(xhr)=>{console.log('请求出错了',xhr);} //失败的回调
				})

				//使用jQuery发送ajax-post(精简版)
				$.post('http://127.0.0.1:8080/test_jquery_post',{school:'atguigu'},(data)=>{
					console.log(data);
					content.append(`<div>汽车名:${data.name},价格:${data.price}</div>`)
				},'json')
			})

		</script>
	</body>
</html>

5.3、ajax的回调地狱问题

回调地狱是指一种不太好的编码形式,是一种套娃现象

html 复制代码
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>11_演示回调地狱</title>
		<script type="text/javascript" src="./js/jquery.min.js"></script>
	</head>
	<body>
		<h3>该页面是测试:演示回调地狱(看代码)</h3>
		<button id="btn1">点我发送请求(jQuery-ajax-get)</button>
		<script type="text/javascript" >
			const btn1 = $('#btn1')

			btn1.click(()=>{
				//使用jQuery发送ajax-get(精简版)
				$.get('http://127.0.0.1:8080/test_jquery_get',{school:'atguigu'},(data)=>{
					console.log(data);
					$.get('http://127.0.0.1:8080/test_jquery_get',{school:'atguigu'},(data)=>{
						console.log(data);
						$.get('http://127.0.0.1:8080/test_jquery_get',{school:'atguigu'},(data)=>{
							console.log(data);
						},'json')
					},'json')
				},'json')
				
			})
		</script>
	</body>
</html>

5.4、什么是同源策略

  1. 同源策略是由Netscape提出的一个著名的安全策略,现在所有支持JavaScript 的浏览器都会使用这个策略。
  2. Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。
  3. 所谓同源是指:协议,域名(IP),端口必须要完全相同 即:协议、域名(IP)、端口都相同,才能算是在同一个域里

5.5、为什么会有跨域这个问题?

原因是浏览器为了安全,而采用的同源策略(Same origin policy)

注意、同源策略是浏览器的一种限制

5.6、没有同源策略的危险场景

危险场景

有一天你刚睡醒,收到一封邮件,说是你的银行账号有风险,赶紧点进www.yinghang.com改密码。你着急的赶紧点进去,还是熟悉的银行登录界面,你果断输入你的账号密码,登录进去看看钱有没有少了,睡眼朦胧的你没看清楚,平时访问的银行网站是www.yinhang.com而现在访问的是www.yinghang.com,随后你来了一条短信,钱没了,这个钓鱼网站做了什么呢?大概是如下思路:

javascript 复制代码
<iframe id="baidu" src="https://www.baidu.com"></iframe>

<script type="text/javascript">
  const iframe = window.frames['baidu']
  const inputNode = iframe.document.getElementById('输入敏感信息的input的id')//现在是拿不到了,你能看到,但是你现在拿不到这里边的任何节点了
  console.log(inputNode.value)
</script>

非同源受到哪些限制

  1. Cookie不能读取;2、DOM无法获得;3、Ajax请求不能获取数据(能发是不能收)

5.7、JSONP解决跨域怎么解决跨域

要明确的是:JSONP不是一种技术,而是程序员"智慧的结晶"(利用了标签请求资源不受同源策略限制的特点)JSONP需要前后端人员互相配合。

前端页面写法

html 复制代码
<body>
	  <button id="btn">按钮</button>
	  <script type="text/javascript">
	    var btn = document.getElementById('btn');
	    btn.onclick = function () {
	      //1. 创建一个script标签
	      var script = document.createElement('script');
	      //2. 设置回调函数
	      window.getData = function (data) {
	        console.log(data);//拿到数据
	      }
	      //3. 设置script标签src属性,填写跨域请求的地址
	      script.src = 'http://localhost:3000/jsonp?callback=getData';
	      //4. 将script标签添加到body中生效
	      document.body.appendChild(script);
	      //5.不影响整体DOM结构,删除script标签
	      document.body.removeChild(script);
	    }
	  </script>
</body>

后端写法

html 复制代码
app.get('/jsonp', (req, res) => {
  //解构赋值获取请求参数
  const {callback} = req.query
  //去数据库查找对应数据
  const data = [{name: 'tom', age: 18}, {name: 'jerry', age: 20}];
  res.send(callback + '(' + JSON.stringify(data) + ')');
})

前端定义函数,后端返回数据的时候调用对用的函数,一切的一切都是因为你定义了对应的函数,这样后端传回来的值才能进行调用

jsonp解决跨域的原理就是绕开了xhr,借助script标签不受同源策略的影响,发送get请求,把数据给拿回来了,有一种前端定义函数,后端调用函数的感觉

html 复制代码
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>Document</title>
	</head>
	<body>
		<h3>当前页面一定不要用服务器去打开,因为要制造跨域问题,用jsonp去解决</h3>
		<button id="btn">点我获取数据</button>
		<script type="text/javascript" >
			
			const btn = document.getElementById('btn')
			btn.onclick = ()=>{
				//1.创建script节点
				const scriptNode = document.createElement('script')
				//2.给节点指定src属性(请求地址)
				scriptNode.src = 'http://localhost:8080/test_jsonp?callback=peiqi'
				//3.将节点放入页面
				document.body.appendChild(scriptNode)
				//4.准备好一个函数
			 	window.peiqi = (a)=>{
					console.log(a);
				}
				//5.移除已经使用过的script节点
				document.body.removeChild(scriptNode)
			}
			//前端给后端发个信息,你小子发信息的时候记住了,那个函数的名字叫做,demo,后端说不行,你这么写的话你得请我吃烧烤,没有原因,想吃烧烤了
		</script>
		
	</body>
</html>

5.8、后台接口框架处理跨域问题

我是后端程序员,做java的处理跨域问题就非常的简单

1、我们有对应的@cors注解、或者配置SpringMVC的对应cors配置项、或者使用nginx解决跨域问题

2、使用vue的脚手架或者React脚手架的代理服务器(这个其实是webpack或者vite里边的一个模块提供的)

3、Node后端框架的处理:

java 复制代码
res.set('Access-Control-Allow-Origin', 'http://localhost:63342');
html 复制代码
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>测试cors解决跨域</title>
	</head>
	<body>
		<h3>当前页面一定不要用服务器去打开,因为要制造跨域问题,测试cors解决跨域</h3>
		<button id="btn">点我获取数据</button>
		<script type="text/javascript" >
			const btn = document.getElementById('btn')
			btn.onclick = ()=>{
				const xhr = new XMLHttpRequest()
				xhr.onreadystatechange = ()=>{
					if(xhr.readyState === 4){
						if(xhr.status === 200){
							console.log(xhr.response);
							console.log(xhr.getAllResponseHeaders());
						}
					}
				}
				xhr.open('PUT','http://localhost:8080/test_put')
				xhr.send()
			}
		</script>
		
	</body>
</html>

5.9、jquery封装的jsonp

java 复制代码
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>Document</title>
		<script type="text/javascript" src="./js/jquery.min.js"></script>
	</head>
	<body>
		<h3>当前页面一定不要用服务器去打开,因为要制造跨域问题,jquery封装的jsonp</h3>
		<button id="btn">点我获取数据</button>
		<script type="text/javascript" >
			const btn = $('#btn')
			btn.click(()=>{
				$.getJSON('http://localhost:8080/test_jsonp?callback=?',{},(data)=>{
					console.log(data);
				})
			})
		</script>
		
	</body>
</html>

页面无刷新获取数据,让用户的体验更好,不用频繁的跳转页面

Access-Control-Allow-Origin

访问-控制-允许-源

Access-Control-Expose-Headers

访问-控制-暴漏-请求头

Access-Control-Allow-Methods

访问-控制-允许-方法

相关推荐
黑客老陈25 分钟前
新手小白如何挖掘cnvd通用漏洞之存储xss漏洞(利用xss钓鱼)
运维·服务器·前端·网络·安全·web3·xss
正小安30 分钟前
Vite系列课程 | 11. Vite 配置文件中 CSS 配置(Modules 模块化篇)
前端·vite
暴富的Tdy1 小时前
【CryptoJS库AES加密】
前端·javascript·vue.js
neeef_se1 小时前
Vue中使用a标签下载静态资源文件(比如excel、pdf等),纯前端操作
前端·vue.js·excel
m0_748235611 小时前
web 渗透学习指南——初学者防入狱篇
前端
z千鑫1 小时前
【前端】入门指南:Vue中使用Node.js进行数据库CRUD操作的详细步骤
前端·vue.js·node.js
m0_748250742 小时前
Web入门常用标签、属性、属性值
前端
m0_748230442 小时前
SSE(Server-Sent Events)返回n ,前端接收数据时被错误的截断【如何避免SSE消息中的换行符或回车符被解释为事件消息的结束】
前端