QX-AI
GPT-4
QX-AI初始化中...
暂无预设简介,请点击下方生成AI简介按钮。
介绍自己
生成预设简介
推荐相关文章
生成AI简介

AJAX简介

AJAX(Asynchronous JavaScript And XML)即异步的 JS 和 XML,发送异步请求,无刷新获取数据

作用:进行前后端交互,前后端交互初步概念

组成:

  1. XMLHttpRequest/Fetch API (异步的与服务器交换数据)
  2. JavaScript/DOM (信息显示/交互)
  3. CSS (给数据定义样式)
  4. XML/JSON (作为转换数据的格式)

优点:

  1. 无需刷新页面而与服务器端进行通信,获取数据。
  2. 根据事件动态获取所需数据,提高效率。

缺点:

  1. 跨域问题
  2. SEO不友好
  3. 无浏览历史

XML可扩展标记语言,用于传输和存储数据

结构上与html标签结构类似,但XML内都是自定义标签

1
2
3
4
<student>
<name>chuckle</name>
<age>19</age>
</student>

发请求

浏览器内建有 XMLHttpRequest 构造函数,通过操控其构造出的对象,就能发送AJAX请求

xhr的 readyState 的属性记录了当前响应处于哪个过程,其值的的变化会触发 readystatechange 事件
0 未调用open方法,1 调用了open还未调用send,2 发送了请求还未收到响应,3 收到了部分响应,4 响应都接收完了

基本属性和方法:

  1. open(请求方法, URL, 是否异步) 初始化
  2. send(请求体) 发送请求
  3. setRequestHeader() 设置请求头
  4. abort() 取消请求
  5. timeout 设置超时时间,超时触发timeout事件

响应相关:

  1. status 响应状态码
  2. statusText 状态字符串
  3. getAllResponseHeaders() 获取所有响应头
  4. response 响应体
  5. responseType 设置响应类型,自动转换
  6. responseXML 接收 xml 格式的响应数据
  7. responseText 接收文本格式的响应数据

GET请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const xhr = new XMLHttpRequest();
xhr.responseType = 'json';
// 第三个参数为是否异步,默认true
xhr.open('GET', 'https://kpb.qcqx.cn/api', true);
xhr.send();
xhr.onreadystatechange = () => {
if(xhr.readyState === 4 && ((xhr.status >= 200 && xhr.status <= 300) || xhr.status === 304)){
let text = xhr.responseText;
console.log(xhr.status);
console.log(xhr.statusText);
console.log(xhr.getAllResponseHeaders());
console.log(xhr.response);
console.log(text);
}
};

POST请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
const xhr = new XMLHttpRequest();
xhr.responseType = 'json';
xhr.open("POST", "https://kpb.qcqx.cn/api/login", true);
// 设置请求头,需在open后send前设置
xhr.setRequestHeader(
"content-type",
"application/x-www-form-urlencoded"
);
xhr.send("username=qx&password=123");
xhr.onreadystatechange = () => {
if (
xhr.readyState === 4 &&
((xhr.status >= 200 && xhr.status <= 300) || xhr.status === 304)
) {
console.log(xhr.status);
console.log(xhr.statusText);
console.log(xhr.getAllResponseHeaders());
console.log(xhr.response);
}
};

超时和错误处理

xhr.timeout 设置超时时间,超时会触发timeout事件
出错(网络错误)会触发error事件

1
2
3
4
5
6
7
8
xhr.timeout = 2000; // 两秒超时
xhr.ontimeout = ()=>{
console.log('连接超时');
}
xhr.onerror = ()=>{
console.log('出错了');
}

取消请求

abort() 可以取消一个请求

1
2
3
4
const xhr = new XMLHttpRequest();
xhr.open('GET', 'https://kpb.qcqx.cn/api', true);
xhr.send();
xhr.abort();// 取消请求

进度

6个进度事件:

  1. loadstart 在接收到响应数据的第一个字节时触发
  2. progress 在接收响应期间持续不断地触
  3. error 在请求发生错误时触发
  4. abort 在因为调用abort()方法而终止连接时触发
  5. load 在接收到完整的响应数据时触发
  6. loadend 在通信完成或者触发error、abort或load事件后触发
  7. timeout 超时发生时触发
1
2
3
4
5
6
7
8
9
// 下载进度
xhr.onprogress = (e)=>{
// loaded 已经下载的字节数,total 总字节数
console.log((e.loaded / e.total * 100).toFixed(2) + '%');
}
// 上传进度
xhr.upload.onprogress = (e)=>{
console.log((e.loaded / e.total * 100).toFixed(2) + '%');
}

JQ-AJAX

使用JQ发送AJAX请求

get和post方法:

  1. $.get(url, [data], [callback], [type])
  2. $.post(url, [data], [callback], [type])
    url:请求的 URL 地址。
    data:请求携带的参数。
    callback:载入成功时回调函数。
    type:设置返回内容格式

通用方法 ajax

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
$.ajax({
url: '',
type: 'GET',
// 请求头
headers: {
a: 100
}
// 数据类型
dataType: 'json',
// 请求体数据
data: {
username: 'qx',
password: '123'
},
// 请求超时时间
timeout: 2000,
// 是否异步处理,默认true
async: true,
// 请求成功回调
success: (data)=>{
console.log(data)
},
// 失败回调
error: (err)=>{
console.log(err)
}
})

Axios

Axios 是一个简单的基于 promise 的 HTTP 客户端,适用于浏览器和 node.js。 Axios 在具有非常可扩展的接口的小包中提供了一个简单易用的库。

使用:

1
npm install axios
cdn
1
<script src="https://cdn.bootcdn.net/ajax/libs/axios/1.3.6/axios.min.js"></script>

常用方法:
用于发送请求:

  1. axios(config): 通用/最本质的发任意类型请求的方式
  2. axios(url[, config]): 可以只指定 url 发 get 请求
  3. axios.request(config): 等同于 axios(config)
  4. axios.get(url[, config]): 发 get 请求
  5. axios.post(url[, data, config]): 发 post 请求
  6. axios.delete(url[, config]): 发 delete 请求
  7. axios.put(url[, data, config]): 发 put 请求
  8. axios.patch(url[, data, config]): 发 patch 请求

基本使用

get请求:axios.get()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 设置baseURL
axios.defaults.baseURL = 'https://kpb.qcqx.cn';
axios.get('/api', {
// url参数,查询字符串
params: {},
// 请求头
headers: {
token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InF4IiwiX2lkIjoiNjQ0NWZhMGYzNTBhYjM2NDM2NDEzNjcwIiwiaWF0IjoxNjgyNDIzOTExLCJleHAiOjE2ODI0MzM5OTF9.pbwr6YjZS-b52xBNISi1O4QemT0Rd-w8oyVI9GpSa6U'
},
}).then(res=>{
// 响应对象
console.log(res);
// 响应体对象
console.log(res.data);
})

post请求:axios.post()

1
2
3
4
5
6
7
8
9
10
11
12
13
axios.post('/api/login', {
// 第二个参数请求体
username: 'qx',
password: '123'
},{
// 第三个参数其余配置
}).then(res=>{
// 响应对象
console.log(res);
// 响应体对象
console.log(res.data);
})

通用方法 axios()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
axios({
url: '/api/login',
method: 'post',
// url参数,查询字符串
params: {},
// 请求头
headers: {},
// 请求体
data: {
username: 'qx',
password: '123'
},
// 请求超时
timeout: 5000
}).then(res=>{
// 响应对象
console.log(res);
// 响应体对象
console.log(res.data);
})

响应结果

  1. config 配置对象,里面有请求方法、请求头、请求url等
  2. data 响应体
  3. headers 响应头
  4. request axios发送请求时创建的原生的AJAX请求对象 XMLHttpRequest
  5. status 响应码
  6. statusText 响应状态字符串
1
2
3
4
5
6
7
8
9
{data: Array(4), status: 200, statusText: 'OK', headers: i, config: {…}, …}
config: {transitional: {…}, adapter: Array(2), transformRequest: Array(1), transformResponse: Array(1), timeout: 0, …}
data: (4) [{…}, {…}, {…}, {…}]
headers: i {cache-control: 'no-cache', content-length: '299', content-type: 'application/json; charset=utf-8', expires: '-1', pragma: 'no-cache'}
request: XMLHttpRequest {onreadystatechange: null, readyState: 4, timeout: 0, withCredentials: false, upload: XMLHttpRequestUpload, …}
status: 200
statusText: "OK"
[[Prototype]]: Object

config配置对象

  1. url 给谁发送请求
  2. method 请求方法
  3. baseURL 设置url的基础结构
  4. params url参数,查询字符串
  5. headers 请求头
  6. data 请求体
  7. timeout 请求超时
  8. transformRequest 对请求的数据进行处理后再发送
    1
    2
    3
    transformRequest: [function (data, headers) {
    return data;
    }],
  9. transformResponse 对响应体进行预处理
    1
    2
    3
    transformResponse: [function (data) {
    return data;
    }],
  10. paramsSerializer url参数序列化,设置url参数的格式
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    paramsSerializer: {
    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

  11. withCredentials: 跨域请求是否携带cookie,默认false
  12. responseType: 响应体结果类型,默认json,array、buffer、document、json、text、stream
  13. responseEncoding: 响应结果的字符集,默认utf8
  14. xsrfHeaderNamexsrfCookieName 防止跨站请求攻击
    1
    2
    3
    4
    5
    xsrfCookieName: '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请求,否者会拦截该请求
  15. maxContentLength: 2000 定义node.js中允许的http响应内容的最大大小
  16. maxBodyLength: 2000 定义http请求内容的最大大小
  17. validateStatus 请求成功的响应码范围
    1
    2
    3
    validateStatus: function (status) {
    return status >= 200 && status < 300; // default
    }
  18. maxRedirects: 21 node.js中允许最大重定向数
  19. proxy: 设置代理
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    proxy: {
    protocol: 'https',
    host: '127.0.0.1',
    hostname: '127.0.0.1' //如果同时定义了“host”,则优先于“host”
    port: 9000,
    auth: {
    username: 'mikeymike',
    password: 'rapunz3l'
    }
    },
  20. cancelToken 用于取消、打断请求,后面有详细介绍
  21. signal 使用AbortController取消Axios请求

全局默认配置

一些重复的配置项可以使用 axios.defaults 进行全局配置

1
2
3
4
// 全局baseURL
axios.defaults.baseURL = 'http://127.0.0.1';
// 设置headers中默认token
axios.defaults.headers.token = "adra2nh12h4jh91";

创建实例对象

axios.create(config) 创建实例对象,传入配置项

当需要大量发送请求时,可以创建一个实例对象,分别传入所需的基础配置项,可以减少代码的书写量,功能和axios几乎一样

1
2
3
const example = axios.create({
baseURL: 'http://127.0.0.1'
});

发请求:

1
2
3
4
5
example({
url: '/api'
}).then(res=>{
console.log(res)
})

拦截器

拦截器是一些函数,分为请求拦截器和响应拦截器,实例对象能单独添加

可以添加多个拦截器,响应拦截器按代码位置先后倒序执行,响应拦截器顺序执行(请求拦截器进入的是堆栈,响应拦截器进入的是队列)

作用:对请求的参数和内容进行检测(判断token,设置请求头)。对响应结果进行预处理(失败提醒、数据格式化)

基础使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 请求拦截器
axios.interceptors.request.use(function () {/*...*/})
// 响应拦截器
axios.interceptors.response.use(function () {/*...*/})
// 实例对象添加拦截器
const instance = axios.create();
instance.interceptors.request.use(function () {/*...*/});
// 移除拦截器
const myInterceptor = axios.interceptors.request.use(function () {/*...*/});
axios.interceptors.request.eject(myInterceptor);
// 清除请求或响应的所有拦截器
const instance = axios.create();
instance.interceptors.request.clear();
instance.interceptors.response.clear();

请求拦截器

对请求的参数和内容进行检测(判断token,设置请求头)

1
2
3
4
5
6
7
axios.interceptors.request.use(function (config) {
// 在发送请求之前做些什么
return config;
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error);
});

响应拦截器

对响应结果进行预处理(失败提醒、数据格式化)

1
2
3
4
5
6
7
axios.interceptors.response.use(function (response) {
// 对响应数据做点什么
return response;
}, function (error) {
// 对响应错误做点什么
return Promise.reject(error);
});

取消请求

1、使用 cancelToken 中断axios请求(v0.22.0后弃用),两种方式:

CancelToken.source 工厂创建取消令牌
1
2
3
4
5
6
7
8
9
10
11
12
13
//创建取消令牌的生成器对象
const CancelToken = axios.CancelToken
//获取令牌对象
const source = CancelToken.source()

// const source = axios.CancelToken.source()
axios.get('/test',{
cancelToken: source.token
})

//取消请求
source.cancel()

将执行函数传递给 CancelToken 构造函数来创建取消标记
1
2
3
4
5
6
7
8
9
10
11
12
let cancel;

axios.get('/user/12345', {
cancelToken: new axios.CancelToken(function(c) {
// 执行器函数接收一个取消函数作为参数
cancel = c;
})
});

// 取消请求
cancel();

2、使用 AbortController :
AbortController 接口表示一个控制器对象,允许根据需要中止一个或多个 Web 请求

通过AbortController创建一个信号对象signal,然后将signal传递给config的signal属性,调用AbortController对象的abort()方法来中止请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 创建AbortController对象
const controller = new AbortController();
// 获取信号对象
const { signal } = controller;
const config = {
method: 'get',
url: "http://localhost:3000/posts",
signal: signal
}
axios(config)
.then((result) => {
console.log(result);
console.log(result.data);
}).catch((err) => {
console.log(err);
});
// 取消请求
controller.abort();

Fetch

get请求:

1
2
3
4
5
6
7
8
9
10
11
12
13
const options = {
method: "GET",
headers: {
token:
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InF4IiwiX2lkIjoiNjQ0NWZhMGYzNTBhYjM2NDM2NDEzNjcwIiwiaWF0IjoxNjgyNDIzOTExLCJleHAiOjE2ODI0MzM5OTF9.pbwr6YjZS-b52xBNISi1O4QemT0Rd-w8oyVI9GpSa6U",
},
};

fetch("https://kpb.qcqx.cn/api", options)
.then((response) => response.json())
.then((response) => console.log(response))
.catch((err) => console.error(err));

post请求:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
const options = {
method: "POST",
headers: {
token:
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InF4IiwiX2lkIjoiNjQ0NWZhMGYzNTBhYjM2NDM2NDEzNjcwIiwiaWF0IjoxNjgyNDIzOTExLCJleHAiOjE2ODI0MzM5OTF9.pbwr6YjZS-b52xBNISi1O4QemT0Rd-w8oyVI9GpSa6U",
"content-type": "application/x-www-form-urlencoded",
},
// 请求体
body: new URLSearchParams({
matter: "吃饭",
data: "2023-04-24",
type: "支出",
account: "20",
remark: "在食堂吃的",
}),
};

fetch("https://kpb.qcqx.cn/api", options)
.then((response) => response.json())
.then((response) => console.log(response))
.catch((err) => console.error(err));

使用AbortController打断fetch请求,在执行fetch请求时,可以通过AbortController创建一个信号对象signal,然后将signal作为配置选项传递给fetch()方法,调用AbortController对象的abort()方法来中止请求。

1
2
3
4
5
6
7
8
9
10
// 创建AbortController对象
const controller = new AbortController();
// 获取信号对象
const { signal } = controller;
// 将信号对象传入fetch配置项
fetch(url, { signal })
.then(response => response.json())

// 调用abort() 中止 fetch 请求
controller.abort();

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
24
fetch(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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// 请求来源白名单
const allowedOrigins = ["127.0.0.1:5500", undefined];
app.use((req, res, next) => {
const origin = req.headers.origin;
// 判断请求来源是否在白名单内
if (
(origin && allowedOrigins.some((item) => origin.includes(item))) ||
allowedOrigins.includes(origin)
) {
// 设置允许跨域的域名,*代表允许任意域名跨域
res.header('Access-Control-Allow-Origin', origin);
// 允许的header类型,如下设置允许自定义header、允许Content-Type为非默认值等,按需删改
res.header('Access-Control-Allow-Headers', "*, Origin, X-Requested-With, Content-Type, Accept, Authorization");
// 跨域允许的请求方式
res.header('Access-Control-Allow-Methods', 'PUT, POST, GET, DELETE, PATCH ,OPTIONS');
// 跨域的时候是否携带cookie
// 需要与 XMLHttpRequest.withCredentials 或 Fetch API 的 Request() 构造函数中的 credentials 选项结合使用
res.header("Access-Control-Allow-Credentials", true);
if (req.method.toLowerCase() == 'options') {
res.send(200); // 让options请求快速结束
}
else {
next();
}
} else {
res.status(403).send('Forbidden');
}
})

jsonp:非官方的解决跨域方法

利用一些天生具有跨域能力的标签发请求,如:img link iframe script。

步骤:

  1. 新建一个script标签
  2. 设置 script 的 src,设置回调函数
  3. 将 script 添加到 body 中
  4. 服务端将数据扔进回调函数中返回
  5. script接收到响应会自动解析运行回调函数,从而获取到数据
简单案例
1
2
3
4
5
6
7
8
9
<script src="https://127.0.0.1:3000/test"></script>
// 后端部分
const data = {
name: 'chuckle'
}
app.all('/test', (req,res)=>{
res.end(`console.log(${data.name})`);
})

JQ实现jsonp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$.getJSON("/api?callback=?", function(data) {
// 获得数据
console.log(data);
})
// 后端设置
const data = {
name: 'chuckle'
}
app.all('/api', (req,res)=>{
// 将数据转化为字符串
let str = JSON.stringify(data);
// 接收回调函数
let cb = req.query.callback;
// 返回数据data
res.end(`${cb}(${str})`);
})