AJAX简介
AJAX(Asynchronous JavaScript And XML)即异步的 JS 和 XML,发送异步请求,无刷新获取数据
作用:进行前后端交互,前后端交互初步概念
组成:
- XMLHttpRequest/Fetch API (异步的与服务器交换数据)
- JavaScript/DOM (信息显示/交互)
- CSS (给数据定义样式)
- XML/JSON (作为转换数据的格式)
优点:
- 无需刷新页面而与服务器端进行通信,获取数据。
- 根据事件动态获取所需数据,提高效率。
缺点:
- 跨域问题
- SEO不友好
- 无浏览历史
XML可扩展标记语言,用于传输和存储数据
结构上与html标签结构类似,但XML内都是自定义标签
1 | <student> |
发请求
浏览器内建有 XMLHttpRequest 构造函数,通过操控其构造出的对象,就能发送AJAX请求
xhr的 readyState 的属性记录了当前响应处于哪个过程,其值的的变化会触发 readystatechange 事件
0 未调用open方法,1 调用了open还未调用send,2 发送了请求还未收到响应,3 收到了部分响应,4 响应都接收完了
基本属性和方法:
- open(请求方法, URL, 是否异步) 初始化
- send(请求体) 发送请求
- setRequestHeader() 设置请求头
- abort() 取消请求
- timeout 设置超时时间,超时触发timeout事件
响应相关:
- status 响应状态码
- statusText 状态字符串
- getAllResponseHeaders() 获取所有响应头
- response 响应体
- responseType 设置响应类型,自动转换
- responseXML 接收 xml 格式的响应数据
- responseText 接收文本格式的响应数据
GET请求
1 | const xhr = new XMLHttpRequest(); |
POST请求
1 | const xhr = new XMLHttpRequest(); |
超时和错误处理
xhr.timeout 设置超时时间,超时会触发timeout事件
出错(网络错误)会触发error事件
1 | xhr.timeout = 2000; // 两秒超时 |
取消请求
abort()
可以取消一个请求
1 | const xhr = new XMLHttpRequest(); |
进度
6个进度事件:
loadstart
在接收到响应数据的第一个字节时触发progress
在接收响应期间持续不断地触error
在请求发生错误时触发abort
在因为调用abort()方法而终止连接时触发load
在接收到完整的响应数据时触发loadend
在通信完成或者触发error、abort或load事件后触发timeout
超时发生时触发
1 | // 下载进度 |
JQ-AJAX
使用JQ发送AJAX请求
get和post方法:
- $.get(url, [data], [callback], [type])
- $.post(url, [data], [callback], [type])
url:请求的 URL 地址。
data:请求携带的参数。
callback:载入成功时回调函数。
type:设置返回内容格式
通用方法 ajax:
1 | $.ajax({ |
Axios
Axios 是一个简单的基于 promise 的 HTTP 客户端,适用于浏览器和 node.js。 Axios 在具有非常可扩展的接口的小包中提供了一个简单易用的库。
使用:
1 | npm install axios |
1 | <script src="https://cdn.bootcdn.net/ajax/libs/axios/1.3.6/axios.min.js"></script> |
常用方法:
用于发送请求:
axios(config)
: 通用/最本质的发任意类型请求的方式axios(url[, config])
: 可以只指定 url 发 get 请求axios.request(config)
: 等同于 axios(config)axios.get(url[, config])
: 发 get 请求axios.post(url[, data, config])
: 发 post 请求axios.delete(url[, config])
: 发 delete 请求axios.put(url[, data, config])
: 发 put 请求axios.patch(url[, data, config])
: 发 patch 请求
基本使用
get请求:axios.get()
1 | // 设置baseURL |
post请求:axios.post()
1 | axios.post('/api/login', { |
通用方法 axios()
1 | axios({ |
响应结果
- config 配置对象,里面有请求方法、请求头、请求url等
- data 响应体
- headers 响应头
- request axios发送请求时创建的原生的AJAX请求对象 XMLHttpRequest
- status 响应码
- statusText 响应状态字符串
1 | {data: Array(4), status: 200, statusText: 'OK', headers: i, config: {…}, …} |
config配置对象
- url 给谁发送请求
- method 请求方法
- baseURL 设置url的基础结构
- params url参数,查询字符串
- headers 请求头
- data 请求体
- timeout 请求超时
- transformRequest 对请求的数据进行处理后再发送
1
2
3transformRequest: [function (data, headers) {
return data;
}], - transformResponse 对响应体进行预处理
1
2
3transformResponse: [function (data) {
return data;
}], - paramsSerializer url参数序列化,设置url参数的格式
1
2
3
4
5
6
7
8
9
10
11
12paramsSerializer: {
encode?: (param: string): string => {
// 自定义操作并返回转换后的字符串
},
// url参数序列化
serialize?: (params: Record<string, any>, options?: ParamsSerializerOptions ),
indexes: false // 数组索引格式 null-无括号,false(默认)-空括号,true-带索引的括号
},
// /api?a=100&b=200
// /api/a/100/b/200
// /api/a.100/b.200 - withCredentials: 跨域请求是否携带cookie,默认false
- responseType: 响应体结果类型,默认json,array、buffer、document、json、text、stream
- responseEncoding: 响应结果的字符集,默认utf8
- xsrfHeaderName和xsrfCookieName 防止跨站请求攻击
1
2
3
4
5xsrfCookieName: 'XSRF-TOKEN', // default
xsrfHeaderName: 'X-XSRF-TOKEN', // default
在客户端第一次发送get请求时,服务器响应数据会携带一个会话cookie(XSRF-TOKEN)一同发送到客户端
在后续请求发送前,http服务会从cookie中读取一个token(默认为XSRF-TOKEN)并且将其设置到HTTP头部(X-XSRF-TOKEN)一同发送到服务器。
然后,服务器端会判断HTTP头部是否携带X-XSRF-TOKEN值,如果该值与之前发送的会话cookie值相同,就可以判定为来自己同一domain请求,否者会拦截该请求 - maxContentLength: 2000 定义node.js中允许的http响应内容的最大大小
- maxBodyLength: 2000 定义http请求内容的最大大小
- validateStatus 请求成功的响应码范围
1
2
3validateStatus: function (status) {
return status >= 200 && status < 300; // default
} - maxRedirects: 21 node.js中允许最大重定向数
- proxy: 设置代理
1
2
3
4
5
6
7
8
9
10proxy: {
protocol: 'https',
host: '127.0.0.1',
hostname: '127.0.0.1' //如果同时定义了“host”,则优先于“host”
port: 9000,
auth: {
username: 'mikeymike',
password: 'rapunz3l'
}
}, - cancelToken 用于取消、打断请求,后面有详细介绍
- signal 使用AbortController取消Axios请求
全局默认配置
一些重复的配置项可以使用 axios.defaults 进行全局配置
1 | // 全局baseURL |
创建实例对象
axios.create(config)
创建实例对象,传入配置项
当需要大量发送请求时,可以创建一个实例对象,分别传入所需的基础配置项,可以减少代码的书写量,功能和axios几乎一样
1 | const example = axios.create({ |
发请求:
1 | example({ |
拦截器
拦截器是一些函数,分为请求拦截器和响应拦截器,实例对象能单独添加
可以添加多个拦截器,响应拦截器按代码位置先后倒序执行,响应拦截器顺序执行(请求拦截器进入的是堆栈,响应拦截器进入的是队列)
作用:对请求的参数和内容进行检测(判断token,设置请求头)。对响应结果进行预处理(失败提醒、数据格式化)
1 | // 请求拦截器 |
请求拦截器
对请求的参数和内容进行检测(判断token,设置请求头)
1 | axios.interceptors.request.use(function (config) { |
响应拦截器
对响应结果进行预处理(失败提醒、数据格式化)
1 | axios.interceptors.response.use(function (response) { |
取消请求
1、使用 cancelToken 中断axios请求(v0.22.0后弃用),两种方式:
1 | //创建取消令牌的生成器对象 |
1 | let cancel; |
2、使用 AbortController :
AbortController 接口表示一个控制器对象,允许根据需要中止一个或多个 Web 请求
通过AbortController创建一个信号对象signal,然后将signal传递给config的signal属性,调用AbortController对象的abort()方法来中止请求
1 | // 创建AbortController对象 |
Fetch
get请求:
1 | const options = { |
post请求:
1 | const options = { |
使用AbortController
打断fetch请求,在执行fetch请求时,可以通过AbortController
创建一个信号对象signal
,然后将signal
作为配置选项传递给fetch()
方法,调用AbortController
对象的abort()
方法来中止请求。
1 | // 创建AbortController对象 |
fetch 没有超时设置,所以需要通过 abort 和 setTimeout 来实现超时
下载进度
fetch 没有 progress 事件,需获取数据流手动计算下载进度。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24fetch(url).then(async res => {
// 克隆响应对象
const response = res.clone();
// 获取数据流
const reader = res.body.getReader();
// 获取数据总字节大小
const total = +res.headers.get('Content-Length');
// 接收到的数据大小
let loaded = 0;
// 读取数据
while (true) {
const { done, value } = await reader.read();
if (done) {
break;
}
loaded += value.length;
console.log((loaded / total * 100).toFixed(2) + '%');
}
return response.text();
}).then(data => {
console.log(data);
}).catch(err => {
console.error(err);
});
跨域
同源策略:浏览器的一种安全策略,同源即协议、域名、端口号必须完全相同。违背同源策略就是跨域
CORS(Cross-Origin Resource Sharing),跨域资源共享。官方的解决跨域方
案,在后端进行设置。
CORS通过设置一个响应头来告诉浏览器,该请求允许跨域,浏览器收到该响应以后就会对响应放行。
express设置cors:
1 | // 请求来源白名单 |
jsonp:非官方的解决跨域方法
利用一些天生具有跨域能力的标签发请求,如:img link iframe script。
步骤:
- 新建一个script标签
- 设置 script 的 src,设置回调函数
- 将 script 添加到 body 中
- 服务端将数据扔进回调函数中返回
- script接收到响应会自动解析运行回调函数,从而获取到数据
1 | <script src="https://127.0.0.1:3000/test"></script> |
JQ实现jsonp
1 | $.getJSON("/api?callback=?", function(data) { |