哈喽,我是Fine
我们在实际项目中少不了与后端通信获取数据,不同的业务请求的方式也不尽相同。大部分时候前端通过Ajax向后端发送数据或获取数据即可满足业务需求,但有时的一些特殊场景可能就Ajax就满足不了了。比如常见的IM需要我们实时的获取信息,就需要通过websocket来实现了。
再比如最近比较火的ChatGPT,它的打字机聊天效果很炫酷,它是通过SSE去实现的。SSE 是一种 HTML5 技术,允许服务器向客户端推送数据,而不需要客户端主动请求。通过 SSE,我们可以在服务器端有新消息时,实时将消息推送到前端,从而实现动态的聊天效果。
今天会为大家分享一篇前端常见的请求方式的文章,以下是正文:
在HTML中,有很多标签可以用来发起HTTP请求。以下是最常见的一些:
<a>
:此标签用于创建一个链接,当用户点击链接时将发起请求到指定的URL。<a href="http://example.com">Visit Example</a>
<img>
:此标签用于加载图片,浏览器会发送请求去获取对应的src的图片资源。<img src="image.jpg" alt="My test image">
<link>
:此标签通常位于HTML文件的<head>
部分,用于引入CSS文件。<link rel="stylesheet" type="text/css" href="styles.css">
<script>
:此标签用于引入JavaScript文件。<script src="script.js"></script>
<iframe>
:此标签用于嵌入另一个HTML页面。<iframe src="http://example.com"></iframe>
<video>
and <audio>
:这两个标签用于嵌入视频和音频内容。<video src="myVideo.mp4" controls></video>
<audio src="myAudio.mp3" controls></audio>
<object>
、<embed>
、<source>
等也能发起请求。请注意,以上的所有请求都是浏览器根据HTML内容自动发起的,不需要做额外的配置。
JavaScript 并不能直接获取到HTML标签请求的结果,但可以通过监听事件和使用一些DOM 属性来间接得到一些信息。以下是一些常见的方法:
load
和 error
事件:var img = new Image();
img.src = 'http://example.com/image.jpg';
img.onload = function() {
console.log('Image has loaded');
};
img.onerror = function() {
console.log('An error occurred while loading image');
};
我们并没有直接获取到图片的内容,但是我们知道图片何时加载成功,或者是否出错,可以获取返回的内容。
AJAXAsynchronous JavaScript and XML
的缩写,即异步的JavaScript和XML。它是一种在不重新加载整个网页的情况下,与服务器交换数据并更新部分网页的技术。
AJAX的核心是XMLHttpRequest对象,它提供了一个API,使得浏览器可以通过JavaScript向服务器发送请求并接收响应。XMLHttpRequest是一个浏览器对象,用于在不重新加载页面的情况下向服务器发送HTTP请求并获取响应。它是AJAX技术的核心组成部分之一,用于实现异步数据交互。
1. 创建ajax对象
2. 调用ajax对象的open 函数 准备发送请求
3. 调用ajax对象的send 函数 发送请求 但是请求还没有到达服务器
4. 调用ajax对象的监听函数 onreadystatechange 监听ajax的创建过程
readystate ajax 的状态码
0 准备创建ajax
new XMLHttpRequest();
1 发送了请求 服务器尚未接到数据 [客户端和服务器 建立了链接]
open()
send()
以下这些状态码 都是服务器对客户端数据进行操作的状态
2 发送了请求 服务器接受到了请求
3 服务器接收到了请求 并且在处理请求
4 服务器处理请求成功 响应给客户端
status 相应状态码 表示 readystate === 4
服务器已经向客户端响应了数据
状态码 会判断 服务器相应数据的状态
200 ok 响应成功
404 响应的页面没有找到
500 服务器产生异常 失败
<button id="btn">获取数据</button>
<h1 id="h1">
希望获取新加载的数据
</h1>
<div id="content">
原有的数据........
</div>
<script>
// 注册事件
const btnNode = document.querySelector("#btn");
const contentNode = document.getElementById('content')
// 注册onclick事件
btnNode.onclick = function () {
// 1. 创建ajax 对象
// 高版本浏览器创建的对象
let xhr;
if (window.XMLHttpRequest) {
xhr = new XMLHttpRequest();
} else {
// IE5 IE6 低版本浏览器
xhr = new ActiveXObject("Microsoft.XMLHTTP")
}
// 2. 准备发送请求
/*
参数
1. 请求方式 get/post/put/delete
2. 请求位置 url
3. 是否是异步请求
true 表示异步
false 表示同步
*/
xhr.open("POST", "http://localhost:3000/api/xhr", true)
// 设置请求头
xhr.setRequestHeader("token", "888888888")
// 3. 发送请求
xhr.send()
// 4. 监听ajax的整个过程
// onreadystatechange 监听ajax 发送的事件
xhr.onload = function () {
console.log('打印***onload')
const data = xhr.responseText;
//获取h1 节点
const h1Node = document.getElementById("h1")
h1Node.innerText = data;
console.log(data);
}
}
</script>
其中第四步可以使用xhr.onload
进行替换
xhr.onload = function(){
const data = xhr.responseText;
//获取h1 节点
const h1Node = document.getElementById("h1")
h1Node.innerText = data;
console.log(data);
}
xhr.onload
和xhr.onreadystatechange
两者的区别xhr.onload
和xhr.onreadystatechange
执行相同的操作:在一个异步请求的各种生命周期阶段接收通知。但是,它们的使用方式有一些差异。
「xhr.onreadystatechange:」
onreadystatechange
事件会在readyState
属性值改变时触发。这意味着你需要检查readyState
值并确定请求是否完成。如果readyState
等于4,那么请求已经完成并且响应已经就绪。
xhr.onreadystatechange = function() {
if (xhr.readyState === 4 && xhr.status === 200) {
console.log(xhr.responseText);
}
};
「xhr.onload:」
相比之下,xhr.onload
事件只在请求成功完成时触发。不需要检查readyState
或状态代码,因为如果触发了onload
事件,那么就可以确保请求已经成功完成。
xhr.onload = function() {
console.log(xhr.responseText);
};
xhr.onload
提供了一个更简洁、更直观的方式来处理成功的HTTP请求。然而,如果你需要更细粒度的控制(例如,你想在请求的不同阶段执行不同的操作),那么xhr.onreadystatechange
可能会是一个更好的选择。
Fetch是 XMLHttpRequest 的升级版,用于在 JavaScript 脚本里面发出 HTTP 请求。
<button id="btn">获取数据</button>
<h1 id="h1">
希望获取新加载的数据
</h1>
<div id="content">
原有的数据........
</div>
<script>
// 注册事件
const btnNode = document.querySelector("#btn");
// 注册onclick事件
btnNode.onclick = function () {
fetch('http://localhost:3000/api/fetch', {
headers: {
token: '66666666666'
}
}).then(res => {
return res.text()
}).then(data => {
const h1Node = document.getElementById("h1")
h1Node.innerText = data;
})
}
</script>
功能点 | XHR | Fetch |
---|---|---|
基本请求、获取响应能力 | √ | √ |
监控请求进度 | √ | x |
监控响应进度 | √ | √ |
Service-Worker中是否可用 | x | √ |
控制cookie的携带 | x | √ |
控制重定向 | x | √ |
请求取消 | √ | √ |
自定义referrer | x | √ |
流 | x | √ |
API风格 | Event | Promise |
活跃度 | x | √ |
WebSocket 是一种在单个 TCP 连接上进行全双工通信的协议。WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就可以直接创建持久性的连接,并进行双向数据传输。
现在许多网站的实时功能(例如聊天,实时游戏等)都是使用 WebSocket 实现的。它解决了 HTTP 协议只能由客户端向服务端发起请求的问题,使得服务端也能主动向客户端发送数据。
<button id="btn">获取数据</button>
<h1 id="h1">
希望获取新加载的数据
</h1>
<div id="content">
原有的数据........
</div>
<script>
// 注册事件
const btnNode = document.querySelector("#btn");
const h1Node = document.getElementById("h1")
// 注册onclick事件
btnNode.onclick = function () {
const socket = new WebSocket('ws://localhost:3000');
socket.onopen = function () {
console.log('连接已建立');
};
socket.onmessage = function (event) {
const data = event.data;
console.log('接收到服务器发送的消息:', data);
h1Node.innerText = data;
};
socket.onclose = function () {
console.log('连接已关闭');
};
// 心跳
setInterval(() => {
socket.send('ping');
}, 3000);
}
</script>
「Beacon
」 API 用于发送异步和非阻塞请求到服务器。这类请求不需要响应。与 XMLHttpRequest 或 Fetch API请求不同,浏览器会保证在页面卸载前,将信标请求初始化并运行完成。
Beacon API 的优点是,它可以在浏览器关闭或离开当前页面时异步发送数据到服务器,而不会阻塞页面的操作或等待服务器的响应。这对于进行统计分析、性能监控和日志记录等后台数据收集的场景非常有用。
<button id="btn">获取数据</button>
<h1 id="h1">
希望获取新加载的数据
</h1>
<div id="content">
原有的数据........
</div>
<script>
// 注册事件
const btnNode = document.querySelector("#btn");
const h1Node = document.getElementById("h1")
// 注册onclick事件
btnNode.onclick = function () {
const data = {
event: '按钮点击',
timestamp: new Date().toISOString(),
userAgent: navigator.userAgent
};
// 调用发送数据的函数, 返回true
const res = navigator.sendBeacon('http://localhost:3000/api/beacon', JSON.stringify(data))
h1Node.innerText = res
}
</script>
Server-Sent Events(SSE)是一种基于HTTP的服务器向客户端发送更新的技术。与WebSockets类似,SSE也允许服务器向客户端推送实时更新。然而,不同于WebSockets提供的双向通信,SSE是单向的:只允许服务器向客户端发送数据。
SSE 是基于HTTP的,因此比WebSocket更容易使用,并且与现有的HTTP基础设施兼容性更好。使用SSE,你可以使用传统的HTTP请求到服务器上开启一个持久连接,服务器可以通过这个连接连续地发送消息。
<button id="btn">获取数据</button>
<h1 id="h1">
希望获取新加载的数据
</h1>
<div id="content">
原有的数据........
</div>
<script>
// 注册事件
const btnNode = document.querySelector("#btn");
const h1Node = document.getElementById("h1")
// 注册onclick事件
btnNode.onclick = function () {
// 创建一个EventSource对象,连接到服务器端的SSE端点
const eventSource = new EventSource('http://localhost:3000/api/sse');
// 监听服务器端发送的消息
eventSource.onmessage = (event) => {
console.log(event.data);
const data = event.data
h1Node.innerText = data;
// 在这里处理服务器端发送的消息
};
// 监听连接关闭事件
eventSource.onclose = () => {
console.log('SSE connection closed');
};
// 监听错误事件
eventSource.onerror = (error) => {
console.error('SSE error:', error);
};
}
</script>
使用koa进行编写:
const Koa = require('koa')
const Router = require('koa-router')
const websockify = require('koa-websocket')
const cors = require('koa2-cors')
const { koaBody } = require('koa-body');
const app = new Koa();
app.use(koaBody());
// 使用koa2-cors中间件解决跨域
app.use(cors())
const router = new Router()
// 使用 koa-websocket 将应用程序升级为 WebSocket 应用程序
const appWebSocket = websockify(app)
// webSocket
appWebSocket.ws.use((ctx, next) => {
// 存储新连接的客户端
clients.add(ctx.websocket)
// 处理连接关闭事件
ctx.websocket.on('close', () => {
clients.delete(ctx.websocket)
})
ctx.websocket.on('message', (data) => {
console.log('打印***data', data)
ctx.websocket.send('pong' + Math.random())
})
ctx.websocket.on('error', (err) => {
console.log('打印***err', err)
clients.delete(ctx.websocket)
})
return next(ctx)
})
// xhr
router.post('/api/xhr', (ctx) => {
ctx.body = 'I am xhr!'
})
// fetch
router.get('/api/fetch', (ctx) => {
ctx.body = 'I am fetch!'
})
// beacon
router.post('/api/beacon', (ctx) => {
const data = ctx.request.body
console.log('打印***data', data)
ctx.body = 'I am beacon!'
})
// sse
router.get('/api/sse', (ctx) => {
ctx.respond = false
ctx.res.writeHead(200, {
"Content-Type": "text/event-stream",
"Cache-Control": "no-cache",
Connection: "keep-alive",
});
// 发送初始事件数据
ctx.res.write(`data: I am sse!\n\n`);
// 定期发送事件数据
setInterval(() => {
ctx.res.write(`data: This is a SSE message at ${new Date().toISOString()}\n\n`);
}, 1000);
})
// 将路由注册到应用程序
appWebSocket.use(router.routes()).use(router.allowedMethods())
// 启动服务器
appWebSocket.listen(3000, () => {
console.log('Server started on port 3000')
})
主要介绍了几种前端常见的请求方式:
❝原文地址:https://juejin.cn/post/7274856771410264075
原文作者: yinuo
本文来自掘金文章分享
❞
觉得本文有用的小伙伴,可以帮忙点个“在看”,让更多的朋友看到咱们的文章。