前言
JavaScript进行网络请求有四种方式,分别为Ajax、Fetch、SSE、WebSocket,下面将分别介绍这几种方式的基本使用。
Ajax
<!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>
<button id="btn">中断</button>
<div id="div"></div>
<script>
const btn = document.getElementById('btn');
const div = document.getElementById('div');
// Ajax
const xhr = new XMLHttpRequest();
// 设置超时时间
xhr.timeout = 5000;
// open 请求方法、请求地址、是否异步
xhr.open("GET", "http://localhost:3000/txt", true);
// 设置超时回调
xhr.ontimeout = () => {
console.log('请求超时');
}
// 设置中断回调
xhr.onabort = () => {
console.log('请求中断');
}
// 设置进度条
xhr.onprogress = (event) => {
div.innerHTML = (event.loaded / event.total * 100).toFixed(2) + '%';
}
// 设置失败回调
xhr.onerror = () => {
console.log('请求失败');
}
// readyState 0 1 2 3 4 分别为未初始化、已经调用open方法、已经调用send方法、正在接收数据、数据接收完毕
// xhr.onreadystatechange = () => {
// if (xhr.readyState === 4 && xhr.status === 200) {
// console.log(xhr.responseText);
// }
// }
// onload 指 readyState === 4
xhr.onload = () => {
if (xhr.status === 200) {
// 如果返回的数据为JSON对象,需要自己parse
console.log(xhr.responseText);
}
}
// 发送请求数据
xhr.send(null);
// 中断请求
btn.addEventListener('click', () => {
xhr.abort();
})
</script>
</body>
</html>
import express from "express";
import fs from "node:fs";
import cors from "cors";
const app = express();
// 处理跨域
app.use(cors());
app.get("/txt", (req, res) => {
const txt = fs.readFileSync("./index.txt", "utf-8");
res.send(txt);
});
app.listen(3000, () => {
console.log("正在监听3000端口...");
});
Fetch
<!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>
<button id="btn">中断请求</button>
<div id="div"></div>
<script>
const btn = document.getElementById('btn');
const div = document.getElementById('div');
// 跨平台:浏览器支持 fetch 函数,NodeJS 18版本之后,fetch方法已经内置,不需要再安装node-fetch
// 默认为 GET 请求
// 与Ajax的区别 默认只支持GET和POST请求,不支持PUT和DELETE请求
// 默认不携带cookie
// 不支持超时控制
// 不支持中断请求
// 进度条实现复杂
const abort = new AbortController();
fetch("http://localhost:3000/txt", {
signal: abort.signal,
method: "DELETE", // 非GET、POST请求,需要后端支持
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
name: "张三"
}),
// credentials: "include" // 携带cookie
})
// 返回的数据格式 text文本、json、blob二进制、formData表单数据、arrayBuffer二进制
.then(response => response.text())
.then(data => {
console.log(data);
}).catch(err => {
console.log(err);
});
// 超时控制
// setTimeout(() => {
// abort.abort();
// }, 5000);
// 中断控制
// btn.onclick = () => {
// abort.abort();
// }
// 进度条
// fetch("http://localhost:3000/txt")
// .then(async (res) => {
// // 克隆一份响应对象
// const response = res.clone();
// // 总数据大小
// const contentLength = res.headers.get("Content-Length");
// // 读取流一次后,就会被消费掉,所以需要重新获取
// const reader = res.body.getReader(); // 读取流
// let current = 0;
// while (true) {
// const { done, value } = await reader.read();
// if (done) {
// break;
// }
// current += value.length || 0;
// div.innerText = (current / contentLength * 100).toFixed(2) + "%";
// }
// return response.text();
// })
// .then(data => {
// console.log(data);
// })
// .catch(err => {
// console.log(err);
// });
</script>
</body>
</html>
import express from "express";
import fs from "node:fs";
import cors from "cors";
const app = express();
// 处理跨域
app.use(cors());
// 支持Fetch的各种请求方式
app.use(function (req, res, next) {
// res.setHeader("Access-Control-Allow-Methods", "*");
res.setHeader("Access-Control-Allow-Methods", "GET POST PUT DELETE");
next();
});
app.get("/txt", (req, res) => {
const txt = fs.readFileSync("./index.txt", "utf-8");
res.send(txt);
});
app.delete("/txt", (req, res) => {
const txt = fs.readFileSync("./index.txt", "utf-8");
res.send(txt);
});
app.listen(3000, () => {
console.log("正在监听3000端口...");
});
SSE
全称为服务器推送(server-sent events),需要后端配合使用
应用场景:大屏可视化、ChatGPT
SSE 为单工通信,即服务器推送消息给客户端 但是客户端不能推送消息给服务器
WebSocke 全双工通信 双方都可以推送消息
<!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>
<div id="div"></div>
<script>
const div = document.getElementById('div');
// sse 服务器推送 server-sent events
const sse = new EventSource('http://localhost:3000/sse');
// 默认为 message, 也可以自定义事件名
// sse.addEventListener("leo", function(event) {
// div.innerHTML = event.data;
// });
sse.addEventListener("message", function(event) {
div.innerHTML = event.data;
});
</script>
</body>
</html>
import express from "express";
import cors from "cors";
const app = express();
// 处理跨域
app.use(cors());
app.get("/sse", (req, res) => {
res.writeHead(200, {
"Content-type": "text/event-stream", // 核心
"Connection": "keep-alive", // 保持长连接,自动重连
});
// 每隔一秒发送一个消息
setInterval(() => {
// res.write("event: leo\n");
res.write(`data: ${new Date().toLocaleTimeString()}\n\n`);
}, 1000);
});
app.listen(3000, () => {
console.log("正在监听3000端口...");
});
WebSocket
可以使用ws库实现
安装依赖
npm i ws
前后端代码
<!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>
<div id="div"></div>
<button id="btn">发送数据给后端</button>
<script>
const div = document.getElementById('div');
const btn = document.getElementById('btn');
// WebSocket
const ws = new WebSocket('ws://localhost:3000');
// 连接成功事件监听
ws.addEventListener("open", (event) => {
console.log('连接成功');
});
ws.addEventListener("message", (event) => {
div.innerHTML = event.data;
})
// 注意不可以发送对象,需要转换成字符串或者二进制
btn.addEventListener('click', () => {
ws.send(JSON.stringify({
type: 'message',
data: 'Hello World'
}));
});
ws.close();
</script>
</body>
</html>
import express from "express";
import cors from "cors";
import { WebSocketServer } from "ws";
const app = express();
// 处理跨域
app.use(cors());
const server = app.listen(3000, () => {
console.log("正在监听3000端口...");
});
// WebSocket 需要依附在 HTTP 服务器上
const wss = new WebSocketServer({ server });
wss.on("connection", (ws) => {
console.log("有新的 WebSocket 连接");
setInterval(() => {
ws.send(new Date().toString());
});
ws.on("message", (msg) => {
console.log("收到消息:" + msg);
});
})