前后端交互
浏览器中的 http 请求
1、URL
2、Links 3、JavaScript(window.location.href = 'http://www.google.com')
4、XMLHttpRequest (XHR)
5、Fetch API
6、Axios
7、WebSocket
实际开发中,XHR 和 Fetch API 是发送异步 HTTP 请求的主要方式,使用时要注意跨域问题和安全问题。
Axios 提供了更多易于使用的功能和选项,使得发送 HTTP 请求更加灵活。
WebSocket 适用于需要实现实时双向通信的应用场景。
理关系
1、Ajax:是一种早期的用于在浏览器中发送异步 HTTP 请求的技术。
Ajax 通过 XMLHttpRequest 对象来发送请求,并通过回调函数处理响应数据。
优点是简单易用
缺点是需要手动编写大量的回调函数来处理请求和响应,代码可读性差
2、Fetch API:是一个新的 JavaScript API,用于在浏览器中发送异步 HTTP 请求。
Fetch 使用 Promise 对象来处理请求和响应,支持链式调用和异步处理,代码可读性较好。
优点是支持跨域请求、使用标准的 Promise API,返回的是 Response 对象,可以使用各种方法处理响应数据
缺点是不兼容低版本的浏览器,需要使用 polyfill 来解决
3、Axios:是一个流行的 JavaScript HTTP 客户端库,用于在浏览器和 Node.js 环境中发送 HTTP 请求。
Axios 使用 Promise 对象来处理请求和响应,支持链式调用和异步处理,代码可读性好。
有点是具有丰富的功能和选项,如请求取消、拦截请求和响应、转换请求和响应数据等
缺点是需要手动引入库文件,增加了代码量和体积
Ajax 的使用
// 1
// 发出HTTP请求
const httpRequest = new XMLHttpRequest();
function handler() {
// ...
}
// 处理上面请求的响应
httpRequest.onreadystatechange = handler;
// 收到响应后需要通过调用HTTP请求对象的open()和方法来实际发出请求
httpRequest.open("GET", "http://www.example.org/some.file", true);
// 第三个参数设置请求是否异步,默认true
httpRequest.send();
// 如果是post数据,需要设置请求的MIME类型
httpRequest.setRequestHeader(
"Content-Type",
"application/x-www-form-urlencoded"
);
// 2
// 处理服务器响应
httpRequest.onreadystatechange = nameOfTheFunction;
// readyState值的含义
// 0(uninitialized)- 请求未初始化
// 1(loading)- 建立服务器连接
// 2(loaded)- 收到请求
// 3(interactive)- 处理请求
// 4(complete)- 请求完成且响应准备就绪
完整示例
<!DOCTYPE html>
<html lang="en">
<head>
<title>Home</title>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width" />
</head>
<body>
<button id="ajaxButton" type="button">Make a request</button>
</body>
<script>
(() => {
let httpRequest;
document
.getElementById("ajaxButton")
.addEventListener("click", makeRequest);
function makeRequest() {
// 1. 创建XMLHttpRequest对象
httpRequest = new XMLHttpRequest();
// 2. 检查是否成功创建XMLHttpRequest对象,如果失败,则显示错误消息并返回false
if (!httpRequest) {
alert("Giving up :( Cannot create an XMLHTTP instance");
return false;
}
// 3. 设置XMLHttpRequest对象的回调函数,当XMLHttpRequest对象的状态发生变化时,将调用该函数
httpRequest.onreadystatechange = alertContents;
// 4. 初始化XMLHttpRequest对象,指定HTTP请求的类型和URL
httpRequest.open("GET", "https://fakestoreapi.com/products/1");
// 5. 发送HTTP请求
httpRequest.send();
}
/*
如果发生通信错误(例如服务器宕机),则在 onreadystatechange 访问响应状态时方法中会抛出异常。
为了缓解这个问题,可以将 if...else 语句包装在 try...catch。
*/
function alertContents() {
try {
if (httpRequest.readyState === XMLHttpRequest.DONE) {
if (httpRequest.status === 200) {
alert(httpRequest.responseText);
} else {
alert("There was a problem with the request.");
}
}
} catch (e) {
alert(`Caught Exception: ${e.description}`);
}
}
})();
</script>
</html>
Fetch API
Fetch API:ES6 之后出现的基于 Promise 的一个强大而灵活的 JavaScript 库,是一个现代的网络请求 API,可以使客户端与服务器之间的通信变得更加容易和直观。它提供了一种简单的方法来发送和接收数据,并支持各种 HTTP 请求和响应类型。
// 发送get
fetch("https://example.com/data.json")
.then((response) => response.json())
.then((data) => console.log(data))
.catch((error) => console.error(error));
// 发送post
const requestOptions = {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ username: "JohnDoe", password: "mySecretPassword" }),
};
fetch("https://example.com/login", requestOptions)
.then((response) => console.log(response))
.catch((error) => console.error(error));
// 处理响应/错误
fetch("https://example.com/data.json")
.then((response) => response.json())
.then((data) => console.log(data))
.catch((error) => console.error(error));
// 处理HTTP错误
fetch("https://example.com/data.json")
.then((response) => {
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.json();
})
.then((data) => console.log(data))
.catch((error) => console.error(error));
// 自定义请求头
const myHeaders = new Headers();
myHeaders.append("Authorization", "Bearer myToken");
fetch("https://example.com/data", { headers: myHeaders })
.then((response) => console.log(response))
.catch((error) => console.error(error));
AbortController:取消Fetch请求
AbortController 是一个标准的浏览器 API,可以用于取消 Fetch 请求及其他支持它的异步操作(如 Axios)。它的核心是通过控制信号来中止异步操作。
// 创建 AbortController 实例
const controller = new AbortController();
const signal = controller.signal;
// 发起异步请求时传入 signal
fetch('https://api.example.com/data', { signal })
.then(response => response.json())
.then(data => console.log(data))
.catch(err => {
if (err.name === 'AbortError') {
console.log('Fetch 被取消');
} else {
console.error('其他错误:', err);
}
});
// 取消请求
controller.abort();
使用 async/await
Fetch API 也可以使用 async/await 语法进行异步请求
async function fetchData() {
try {
const response = await fetch("https://example.com/data.json");
const data = await response.json();
console.log(data);
} catch (error) {
console.error(error);
}
}
fetchData();
Axios
const instance = axios.create({
baseURL: "https://some-domain.com/api/",
timeout: 1000,
headers: { "X-Custom-Header": "foobar" },
});
// 发送get
axios
.get("/user?ID=12345")
.then(function (response) {
// handle success
console.log(response);
})
.catch(function (error) {
// handle error
console.log(error);
})
.finally(function () {
// always executed
});
// 也可以用以下方式
axios
.get("/user", {
params: {
ID: 12345,
},
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
})
.finally(function () {
// always executed
});
async function getUser() {
try {
const response = await axios.get("/user?ID=12345");
console.log(response);
} catch (error) {
console.error(error);
}
}
// GET request for remote image in node.js
axios({
method: "get",
url: "http://bit.ly/2mTM3nY",
responseType: "stream",
}).then(function (response) {
response.data.pipe(fs.createWriteStream("ada_lovelace.jpg"));
});
const { data } = await axios.post("/user", document.querySelector("#my-form"), {
headers: {
"Content-Type": "application/json",
},
});
const { data } = await axios.post(
"https://httpbin.org/post",
{
firstName: "Fred",
lastName: "Flintstone",
orders: [1, 2, 3],
photo: document.querySelector("#fileInput").files,
},
{
headers: {
"Content-Type": "multipart/form-data",
},
}
);
// 设置请求头
axios
.get("/api/users", {
headers: {
Authorization: "Bearer " + token,
},
})
.then((response) => console.log(response.data))
.catch((error) => console.log(error));
// 拦截请求和响应
axios.interceptors.request.use(
(config) => {
// Do something before request is sent
return config;
},
(error) => {
// Do something with request error
return Promise.reject(error);
}
);
axios.interceptors.response.use(
(response) => {
// Do something with response data
return response;
},
(error) => {
// Do something with response error
return Promise.reject(error);
}
);
取消axios请求:CancelToken 或 AbortController
Axios 提供了取消请求的内置支持,使用 CancelToken 或 AbortController 来取消请求。最新的版本更倾向于使用 AbortController。
使用AbortController
:
const controller = new AbortController();
// 发送 axios 请求,传递 signal 参数
axios.get('https://api.example.com/data', {
signal: controller.signal
})
.then(response => {
console.log(response.data);
})
.catch(err => {
if (err.name === 'AbortError') {
console.log('Axios 请求被取消');
} else {
console.error('其他错误:', err);
}
});
// 取消请求
controller.abort();
使用CancelToken
:
const CancelToken = axios.CancelToken;
let cancel;
// 发送请求,传递 cancelToken 参数
axios.get('https://api.example.com/data', {
cancelToken: new CancelToken(function executor(c) {
cancel = c;
})
})
.then(response => {
console.log(response.data);
})
.catch(err => {
if (axios.isCancel(err)) {
console.log('Axios 请求被取消');
} else {
console.error('其他错误:', err);
}
});
// 取消请求
cancel('请求被手动取消');
Fetch API 和 Axios
Ajax 实际上不是一个特定的技术,而是一系列技术的统称,通常将其默认为是 XMLHttpRequest
Fetch API 是 ES6 之后出现的一个新的基于 Promise 的新 API,可以认为是 XMLHttpRequest 的最新替代品
Axios 则是一个专门用于 HTTP 请求的库,也是基于 Promise
Promise模拟取消效果
Promise 本身没有提供取消的机制,但可以通过一些技巧来模拟取消的效果。可以通过包装 Promise 来实现取消功能。
function cancellablePromise(promise) {
let isCancelled = false;
const wrappedPromise = new Promise((resolve, reject) => {
promise
.then(value => {
if (!isCancelled) {
resolve(value);
}
})
.catch(error => {
if (!isCancelled) {
reject(error);
}
});
});
return {
promise: wrappedPromise,
cancel() {
isCancelled = true;
}
};
}
// 使用
const { promise, cancel } = cancellablePromise(
new Promise((resolve) => setTimeout(() => resolve('Done!'), 5000))
);
promise.then(value => console.log(value)).catch(err => console.error(err));
// 在某个条件下取消
cancel();
参考
https://juejin.cn/post/7211103821082394682?searchId=202408162056396170A99E42415DB9E588