【Ajax原生+封装+扩展】入门到入土,这一篇就够了
文章目录
-
- 前言
-
- 0.1 XML简介
- 0.2 AJAX 特点
- 1. HTTP相关
-
- 1.1 HTTP请求交互基本过程
- 1.2 HTTP请求报文
- 1.3 HTTP响应报文
- 1.4 post请求体参数格式
- 1.5 不同类型的请求及作用
- 1.6 一般http请求与Ajax请求的区别
- 1.7 http状态码
- 2. 原生AJAX基本使用(XHR)
-
- 2.1 准备工作
- 2.2 请求的基本操作
- 2.3 如何设置请求头
- 2.4 JSON数据请求
- 2.5 nodemon
- 2.6 请求超时和网络异常
- 2.7 取消请求
- 28 请求重复发送问题
- 2.9 解决IE缓存问题
- 2.8 Ajax函数封装
- 3. 在jQuery中发送Ajax请求
-
- 3.1 GET请求
- 3.2 POST请求
- 3.3 通用方法
- 4. axios发送Ajax请求
-
- axios函数发送请求
- 5. 跨域
-
- 5.1 同源策略
- 5.2 解决方案1 ——JSONP
- 5.3 解决方案2——CORS
前言
AJAX 全称为Asynchronous JavaScript And XML
,也就是异步的JS和XML
- 通过AJAX,可以在无刷新页面的情况下,向服务器发送异步请求,并获取来自服务端的数据,这也是AJAX最大的优势:无需刷新获取数据
AJAX的使用在网页中非常常见,比如上新闻网,往下刷着刷着,需要加载一会才能显示下面的信息,这就是触发到底事件,浏览器通过AJAX获取到新的数据,然后通过JS创建元素显现在网页中
异步的JS相信无需讲解,下面对XML简单进行说明
0.1 XML简介
XML 是可扩展标记语言,被设计用来传输和存储数据
XML和HTML在结构上类似,不同的是HTML里是预定义标签,如
而XML中没有预定义标签,均为自定义标签,用来表示(“形容”)数据
如下栗子:
<student> <name>张三</name><age>18</age></student>//这就是一个承载某位学生的XML数据段
最早AJAX中传送和存储数据用的就是XML,不过,现在已经被JSON
替代,
如下:
{"name":"张三","age":18}
JSON
是一种纯数据格式,只包含属性- 简洁,在数据转换更加容易,灵活度远胜于 XML
0.2 AJAX 特点
-
优点
- 无需刷新页面而与服务器进行通信
- 允许根据用户事件来更新部分页面内容
-
缺点
-
无浏览历史,无法回退
没有页面刷新
-
存在跨域问题
无法从一个服务向另一个服务发送请求
-
SEO
不友好AJAX获取的数据,爬虫爬不到(感兴趣可以去了解一下
SEO
),简单说明就是百度搜不到这些数据
-
1. HTTP相关
首先我们需要对HTTP有一定的了解
全名为超文本传输协议,其实就是一个互联网的规定,简单理解就是统一语言
想要全面的学习http,MAD文档是个不错的选择
点此可跳转
1.1 HTTP请求交互基本过程
1.2 HTTP请求报文
包括四部分
-
行
行包括三部分,请求类型(GET、POST等),URL路径,HTTP版本/
1.1or1.0
-
头
请求体类型
Host: atguigu.comCookie: name=giuguContent-type: applicatiion/x-www-form-urlencodedUser-Agent: chrome 83//键值对格式
-
空行
-
体
GET请求时,请求体为空,POST请求时,请求体可不为空
username=admin&password=admin
1.3 HTTP响应报文
四部分
-
行
包含三部分,协议版本——HTTP/1.1,响应状态码——如200表示OK(如常见的404),响应状态字符串
-
头
格式跟请求报文头一样
-
空行
-
体
主要返回结果
html文本、json文本、js、css、图片...
1.4 post请求体参数格式
-
Content-Type:application/x-www-form-urlencoded;charset=utf-8
用于键值对参数,参数的键值用
=
链接,参数之间用`&连接 -
Content-Type: application/json;charset=utf-8
用于
json
字符串参数 -
Content-Type: multipart/form-data
用于文件上传请求
1.5 不同类型的请求及作用
-
GET
:从服务端读取数据 -
POST
:向服务端添加新数据 -
PUT
:更新服务端数据 -
DELETE
:删除服务端数据
也就是查增改删
1.6 一般http请求与Ajax请求的区别
- Ajax是特殊的http请求
- 对于浏览器端,只有
XHR
,和fetch
发出的才是Ajax请求,其他所有都是非Ajax请求 - 浏览器响应:
- 接收一般http请求后,浏览器一般会直接显示响应体的数据,也就是刷新/跳转页面
- 接收Ajax请求后,浏览器并不会刷新,只是通过回调函数,传入响应体的数据
1.7 http状态码
无需考究太多,能知道代表什么就行,http状态码是在响应报文的行里面的。
200~300
表示OK,不过用得多的是200
404
表示服务端未接收到请求
500
服务器端错误,有时候就是服务器代码编译出错
这几个是比较常见的,后面发现没见过的一定要灵活应用搜索引擎
2. 原生AJAX基本使用(XHR)
xhr,全称为XMLHttpRequest
,用于与服务器交互数据,是ajax功能实现所依赖的对象
2.1 准备工作
我们接下来通过案例实现Ajax的交互,从而学习Ajax
首先我们需要在服务端做一些准备
- 安装node.js
官方链接
打开命令行输入node -v若出现某个版本号,说明安装成功
- 安装express框架
利用命令行
npm init --yes初始化环境npm i express 下载express包,建议使用管理员身份打开VScode或命令行,否则可能出现err
2.2 请求的基本操作
如何建立浏览器与服务端联系,下面通过一个小例子说明
服务端:
//引入expressconst express = require('express')//创建应用对象const obj = express();//创建路由规则//request 对请求报文的封装//response 对响应报文的封装obj.get('/server', (request, response)=>{ response.setHeader('Access-Control-Allow-Origin', '*'); response.send('HELLO AJAX');})//监听端口启动服务obj.listen(8000, ()=>{ console.log('服务已经启动,8000端口监听中...');})
html:
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>AJAX GET 请求</title> <style> #result{ width: 200px; height: 200px; border: 5px solid #90b; } </style></head><body> <button>点击此发送请求</button> <div id="result"></div> <script> const btn = document.getElementsByTagName('button')[0]; const result = document.getElementById('result'); //注册事件 btn.onclick = function(){ //四步建立关系 //1,创建对象 const xhr = new XMLHttpRequest(); //2,初始化,设置请求方法和URL xhr.open('GET', 'http://127.0.0.1:8000/server'); //3,发送 xhr.send(); //4,事件绑定,处理返回的结果 xhr.onreadystatechange = function(){ //判断是否返回了所有结果 if(xhr.readyState === 4){ //判断是否成功,通过状态码 if(xhr.status >= 200 && xhr.status <=300){ //设置result的文本 result.innerHTML = xhr.response; } } } } </script></body></html>
在VScode里打开终端,执行服务端js文件
node .\server.js
此时设置的监听器打开
再把html在浏览器中打开,便可实现交互效果,你可以点点那个按钮看看哦
上述的GET请求的案例,作用就是在服务端获取信息,大家还可以试试类型完成交互,本文主讲GET 和POST两种类型
补充:
GET请求设置参数
大家有时可以看到某些URL后面会带着一长串东西,那就是浏览器向服务端传输的数据参数
格式如下:
在域名后加上?
作为分割,紧接着用参数=值
&参数=值
的循序叠加
栗子如下:
http://127.0.0.1:8000/server?a=100&b=200&c=300
//在代码里则表现为xhr.open('GET', 'http://127.0.0.1:8000/server?a=100&b=200&c=300');
上述请求的基本操作对于GET和POST均成立
这里提的是他们设置参数方式的不同
对于POST设置参数则为:
xhr.send('a=100&b=200&c=300');
事件绑定:
也就是第四个步骤,目前较新的用法是onload事件
xhr.onload = function(){ if(xhr.status >= 200 && xhr.status <=300){ //设置result的文本 result.innerHTML = xhr.response; }}
当然,两个方法都是可用的
2.3 如何设置请求头
报文的其他部分我们都以及有了设置的方法,还差一个请求头
这个也是通过XHR对象的一个方法实现的
语法如下:
xhr.setRequestHeader('Content-Type', 'application/x-www-from-urlencoded');
需要注意的是,当你使用post类型时,记得把服务端文件中的get改为post哦,否则无法接受到请求
2.4 JSON数据请求
接下来同样用一个例子让我们理解JSON
首先先有几个知识点
我们知道,JSON就是存储数据的,没有标签,没有函数
那么如果我们想要获取到服务端的数据
const data = { name : 'zhangsan';}
那么从前面学的知识,我们可以想到,在JS文件中,对
response.send('...');
进行修改即可,需要注意的是,该send方法只能传递字符串
那我们还可以利用一个对象的方法
let str = JSON.stringify(data);
对该data对象进行字符串转换,那么合起来代码就是:
const data = { name : 'zhangsan'};let str = JSON.stringify(data);response.send(str);
那么在浏览器端,就会接收到这样一段数据
name : 'zhangsan'
如果我想得到值,去掉这个name怎么办?
在日常的应用中,大多数情况也是不需要这个name属性
我们可以在浏览器端设置
-
第一种,手动设置
let data = JSON.parse(xhr.response);result.innerHTML = data.name;
-
第二种,自动转化
在XHR对象中,有一个设置返回数据类型的格式
我们可以这样设置它,
xhr.responseType = 'json';
这句代码只需要在前面定义,后面只要我们需要用到某个值,都可以直接
result.innerHTML = xhr.response.name;
灰常方便!!
服务端:
const express = require('express')const app = express();app.all('/server', (request, response) => { // 设置响应头, 设置允许跨域 response.setHeader('Access-Control-Allow-Origin', '*'); // 响应一个数据 const data = { name: 'zhangsan' }; // 对 对象 进行 字符串 转换 let str = JSON.stringify(data) // 设置响应体 response.send(str);});
html:
<!DOCTYPE html><html lang='en'> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewpport" content="width=device-width, initial-scale=1.0"> <title>JSON</title> <style> #result{ width: 200px; height: 200ox; border: 5px solid #90b; } </style> </head> <body> <div id="result"></div><script> const result = document.getElementById('result'); //绑定键盘按下事件 window.onkeydown = function(){ //发送请求 const xhr = new XMLHttpRequest(); //响应体数据自动转换为JSON xhr.responseType = "json"; //初始化 xhr.open('GET', 'http://127.0.0.1:8000/server'); //发送 xhr.send(); //事件绑定 xhr.onreadystatechange = function(){ if(xhr.readyState === 4){ if(xhr.status >= 200 & xhr.status <= 300){//手动数据转化//let data = JSON.parse(xhr.response);//result.innerHTML = data.name;//自动result.innerHTML = xhr.response.name; } } } } </script> </body></html>
2.5 nodemon
这里先来介绍一个工具
我们知道,当我们对服务端文件进行修改时,需要重新启动服务才能生效,这就有点繁琐了,而这个工具可以自动检测我们的文件是否修改,如果修改,它会帮我们自动重新启动服务
安装也是非常简单,在终端写下以下代码
npm install -g nodemon
等待安装,启动服务把node的代码换成用这一串代码,就代表使用这个工具拉
nodemon server.js
2.6 请求超时和网络异常
用户在浏览网页时时常会发生网络异常,或者网络速率低超时现象
这时我们可以提醒用户,“稍后重试” ——“友好信息,保证用户体验”
//这是设置超时的对象属性//此处设置为2秒xhr.timeout = 2000;//超时时间发生,调用回调函数xhr.ontimeout = function(){ alert('网络超时,请稍后重试')}//网络异常事件发生,调用回调函数xhr.onerror = function(){ alert('网络异常,请稍后重试');}
2.7 取消请求
有时用户可能因为某些原因,想要取消请求操作,如等的不耐烦,按错了
这时候,我们可以使用XHR对象的abort方法
xhr.abort();//注意,一般得设置个事件,把上面的代码放进去,比如按钮,当按下按钮,取消请求
28 请求重复发送问题
当用户快速触发事件多次发送请求,服务器压力变大,性能降低
解决方法:
重复发送请求时,将上一次未完成的请求取消
//创建一个判断是否正在发送请求的变量let isSending = false;//在事件内判断是否正在发送,如果是,取消请求然后再创建新请求//在判断之后将上述变量改为真(写在初始化前面)//这样用户发送第二次请求就会执行该if语句if(isSending) xhr.abort();x = new XMLHttpRequset();isSending = true;...
2.9 解决IE缓存问题
在某些浏览器如IE,由于缓存机制的存在,Ajax只会发送第一次的请求,剩余多次请求不会再发送给浏览器而是直接加载缓存中的数据
解决方法:
浏览器的缓存是通过URL地址记录的,因此我们只需要修改URL,多次请求也可以发送啦
xhr.open('GET','/server?t='+Date.now());//给它加个时间戳,保证每次请求的URL都会不同
2.8 Ajax函数封装
重点来了,Ajax请求发送步骤不少,一次两次还行,但是实际开发中我们会经常用到Ajax请求,这时候如果还一个一个写就多出了很多重复代码,因此我们一般会用一个函数封装Ajax的基本操作
function ajax (options){ //设置默认值 var defaults = { type: 'get', url: '', data: {}, header: { 'Content-Type': 'appliction/x-www-form-urlencoded' }, success: function(){}, error: function(){ alert('请求错误'); } }//用option覆盖defaults对象,传递的参数没有设置就用默认值 Object.assign(defaults, options); var xhr = new XMLHttpRequest(); //获取请求参数字符串 var params = ''; for(var attr in defaults.data){ params += attr + '=' + defaults.data['attr'] + '&'; } params = params.substring(0, [params.length - 1]); //判断请求方式并发送请求体 if(defaults.type == 'get'){ defaults.url = defaults.url + '?' + params; } xhr.open(defaults.type, defaults.url); if(defaults.type == 'post'){ xhr.send(params); }else{ xhr.send(); } //获取返回的数据 xhr.onload = function(){ var contentType = xhr.getResponseHeader('Content-Type'); var responseText = xhr.responseText; if(contentType.includes('application/json')){ responseText = JSON.parse(responseText); } if(xhr.status == 200){ defaults.success(responseText, xhr); }else{ defaults.error(responseText, xhr); } } }
3. 在jQuery中发送Ajax请求
3.1 GET请求
$('button').btn(0).click(function(){ $.get('http://127.0.0.1:8000/server', {a:100, b:200}, function(data){ console.log(data);//这里获得从服务端传来的数据进行处理 } )})
3.2 POST请求
$('button').btn(0).click(function(){ $.post('http://127.0.0.1:8000/server', {a:100, b:200}, function(data){ console.log(data);//这里获得从服务端传来的数据进行处理 } )})
上面两个的格式就是
$.get/post(url, [data], [callback], [type])
type可选,类似原生的xhr.responseType
$其实也就是一个对象
3.3 通用方法
$.ajax({ url: 'http://127.0.0.1:8000/server', data: {a:100, b:200}, type: 'GET', dataType: 'json', //回调函数 success: function(data){ console.log(data); }, //还可以设置超时时间,时间到取消请求 timeout: 2000, //失败回调 error: function(){ console.log('貌似出现了点问题'); }});
4. axios发送Ajax请求
浅浅介绍一下,axios是目前非常流行的Ajax封装库,可以很方便地实现Ajax请求的发送
到bootcdn搜索把axios的scrip标签格式复制拿过来就行了
现在发送请求(GET)
//GET请求axios.get('http://127.0.0.1:8000/server', { //url参数 params: { id:100, vip:7 }, //请求头信息 headers:{ name: 'zhangsan', age: 18 }}).then(value => { console.log(value);})//相当于回调函数
axios里还有一个baseURL
当你在前面配置了
axios.defaults.baseURL = "http://127.0.0.1:8000";
后面URL设置就可以省略这前面的一部分
axios.get('/server', ...)
(POST)
请求体设置
axios.post('/server', { username: 'admin', password: 'admin'}, { params:{ id:200, vip:7 } headers: { height: 180, weight:150}})
axios一般设置三个参数
axios函数发送请求
非常清晰,十分推荐
axios({ method: 'POST', url: 'http://127.0.0.1:8000/server', //这里还可以用baseURL简化一下的 parans: { level: 30, vip:5 }, headers: { a: 100; b:200 }, //这里是请求体参数 data:{ username: 'admin', password: 'admin' }})
5. 跨域
5.1 同源策略
同源:协议、域名、端口号必须完全一样
注意,上述一个不同就是违背同源,也就是跨域
5.2 解决方案1 ——JSONP
非官方,是程序员自己想出来的
只支持GET请求
原理:
HTML中有些网页自带跨域能力,如img
、link
、script
而JSONP就是利用script标签实现跨域请求的
具体使用:
- 动态创建
script
标签 - 设置src属性,设置回调函数
- 一般大家会把这里动态添加的script标签添加到body中
var script = document.creatElement('script');script.src = "http://localhost:52330/...";function callback(data){ ...};document.body.appendChild(script);
注意:
由于返回的字段相当于写在script标签里,所以应该为JS代码,才可以被解析
5.3 解决方案2——CORS
跨域资源共享,官方解决方案,不需要在客户端做任何特殊操作,完全在服务器中处理,支持get和post
- 跨域资源共享标准新增了一组HTTP首部字段,允许服务器声明哪些源站通过浏览器有权限访问哪些资源
原理:
通过设置响应头来告诉浏览器,该请求允许跨域,浏览器收到响应后就会给请求放行
具体使用:
重心就是服务端的设置:
router.get('/ajaxtest', function(require, response)=>{ //设置响应头 response.setHeader('Access-Control-Allow-Origin', '*'); //星号表示统配,都可以跨域//如果只想能跨域某个网页//response.setHeader('Access-Control-Allow-Origin', 'http://127.0.0.1:8000'); })
函数
3. 一般大家会把这里动态添加的script标签添加到body中
var script = document.creatElement('script');script.src = "http://localhost:52330/...";function callback(data){ ...};document.body.appendChild(script);
注意:
由于返回的字段相当于写在script标签里,所以应该为JS代码,才可以被解析