前端请求的历史可以追溯到早期网页浏览器和前端技术的起步。随着 Web 技术的发展,前端请求的方式也经历了多个阶段,从最初的简单页面刷新,到现代的异步请求和复杂的数据交互。
下面是前端请求发展的主要历史阶段:
前后端不分离
前后端不分离 (也称为传统单体开发模式)是一种在 Web 开发中,前端和后端代码紧密集成在同一个应用程序中的开发方式。在这种模式下,前端和后端通常是同一个应用的一部分,共享一个代码库,且前端页面由后端直接渲染。
这是非常早期的软件开发时代,那个时候JS只做一些简单的脚本工作。大部分产品是PHP、Java和C#等开发的产品,比如JSP页面,可能大家对JSP有一点印象。
假设开发一个电子商务网站,使用单体开发模式是这样做的:
- 用户在浏览器中访问一个商品页面。
- 后端通过某个模板引擎(比如 Thymeleaf、JSP 等)将页面模板和从数据库获取的商品数据结合起来,生成一个完整的 HTML 页面。
- 然后,这个 HTML 页面被发送到浏览器并呈现给用户。
- 当用户想要查看其他商品时,浏览器再次向服务器请求新的 HTML 页面,整个过程就像刷新一样。
整个流程看起来比较像服务端渲染,有扩展性差,用户体验差和性能差等缺点。站在2025年这个时间点,没必要深究,不再过多赘述
JQuery
时间到了2005年,微软在IE浏览器中推出Ajax技术。
AJAX(Asynchronous JavaScript and XML)是一种用于创建快速动态网页的技术,它可以使网页在不重新加载整个页面的情况下,与服务器进行数据交换并更新部分网页内容。这样可以提升用户体验,因为页面可以更快地响应用户的操作。
与Ajax同时期流行的还有JQuery,在项目中使用ajax主要通过JQuery封装的Ajax方法。使用 jQuery 发送请求数据非常简单,jQuery 提供了多种方法来处理 HTTP 请求,包括 .ajax()
、.get()
、.post()
等。下面我会分别介绍这些常见的方法,并展示如何使用它们发送请求
下面是使用$.get
调用数据接口的例子
js
$.get('http://jsonplaceholder.typicode.com/posts', function(response) {
console.log(response);
});
相比使用原生ajax,$.get
使用方式非常简单
使用$.post
向服务端发送数据
js
$.post('/server-endpoint', { data: 'example' }, function(response) {
console.log(response); // 假设服务器返回一个 JSON 对象
}).fail(function() {
console.log("Error occurred.");
});
JQuery提供成功响应、失败等多种状态下处理网络请求的场景。在Vue/React框架流行以前,基本上所有的项目中使用JQuery提供的请求方法
但是现在的前端项目基本上都是使用React/Vue等现代化前端框架开发,基本上不会引用JQuery。只有老旧项目依旧使用JQuery,但是新版本的浏览器都支持Promise和Fetch Web API,即使在老旧项目中添加接口调用逻辑,也可以完全不用JQuery的ajax系列方法
axios
随着时间的推移,TC39在ES6中提出Promise
机制。
Promise 是一种用于处理异步操作的 JavaScript 对象。它代表一个可能在未来某个时间点才会完成的操作,并且可以在操作完成时提供结果或失败的原因。简单来说,Promise 就是一个"承诺",它表示某个操作最终会完成并返回结果,或者如果操作失败,它会提供失败的原因。Promise的出现让JS对异步的表现形式发生巨大变化,这个时候JS社区出现 axios 这个用于网络请求第三方工具
Axios 是一个基于 Promise 的 JavaScript HTTP 客户端 ,用于浏览器和 Node.js 中发送 HTTP 请求。它简化了与服务器进行交互的过程,支持 异步 操作并处理请求和响应数据。Axios 是当前前端开发中非常流行的库,特别是在与 RESTful API 或后端进行数据交换时。
Axios 的主要特点:
- Axios 使用 Promise 来处理异步操作,可以使用
then()
和catch()
方法进行链式调用,或结合async/await
语法进行更简洁的代码编写。
js
axios
.get("/api/data")
.then((response) => {
console.log(response.data); // 处理返回的数据
})
.catch((error) => {
console.error(error); // 错误处理
});
- 支持请求和响应拦截器:Axios 提供了请求和响应的拦截器,可以在请求发送之前或响应到达时对其进行处理。例如,可以在请求头中添加认证令牌,或者在响应时统一处理错误信息。
请求拦截器:
js
axios.interceptors.request.use((config) => {
// 在请求发送之前做一些处理
config.headers.Authorization = "Bearer token";
return config;
});
响应拦截器:
js
axios.interceptors.response.use(
(response) => response, // 响应成功时的处理
(error) => {
console.error(error); // 响应失败时的处理
return Promise.reject(error);
}
);
-
支持各种 HTTP 方法:
- Axios 支持 GET 、POST 、PUT 、DELETE 等常见的 HTTP 请求方法,使用简单方便。
示例:
lessaxios.get('/api/data'); // GET 请求 axios.post('/api/data', { ... }); // POST 请求 axios.put('/api/data/1', { ... }); // PUT 请求 axios.delete('/api/data/1'); // DELETE 请求
-
自动转换响应数据:
- Axios 会自动将响应数据转换成 JSON 格式,这样你可以直接访问响应体的数据,不需要额外的解析。
-
支持取消请求:
- Axios 支持取消请求。你可以通过
CancelToken
来取消请求,这对于避免不必要的请求(比如用户输入搜索词时发出的多个请求)非常有用。
示例:
iniconst source = axios.CancelToken.source(); axios.get('/api/data', { cancelToken: source.token }).then(response => { console.log(response); }).catch(error => { if (axios.isCancel(error)) { console.log('请求被取消'); } else { console.error(error); } }); // 取消请求 source.cancel('请求已取消');
- Axios 支持取消请求。你可以通过
-
支持跨浏览器请求(CORS):
- Axios 默认支持 跨源请求(CORS) ,可以处理不同域之间的请求问题,前提是服务器正确配置了 CORS 头。
-
支持上传和下载进度监控:
- Axios 支持通过配置
onUploadProgress
和onDownloadProgress
监控文件上传和下载的进度。
示例:
javascriptaxios.post('/upload', formData, { onUploadProgress: function (progressEvent) { var percentCompleted = Math.round((progressEvent.loaded * 100) / progressEvent.total); console.log('上传进度: ' + percentCompleted + '%'); } });
- Axios 支持通过配置
Axios 和 jQuery 的对比:
特性 | Axios | jQuery |
---|---|---|
基于 | 基于 Promise | 基于回调函数 |
支持的请求 | 支持 GET、POST、PUT、DELETE 等请求 | 支持 GET 和 POST 请求,较少其他类型 |
浏览器支持 | 支持现代浏览器和 Node.js | 支持老版本浏览器(包括 IE) |
请求拦截器 | 支持请求和响应拦截器 | 不支持请求和响应拦截器 |
跨域请求 | 支持 CORS | 支持 CORS(但需要服务端支持) |
请求取消 | 支持请求取消(通过 CancelToken ) |
不支持请求取消 |
支持进度 | 支持文件上传/下载进度 | 不支持文件上传/下载进度 |
数据处理 | 自动处理 JSON 数据转换 | 需要手动处理 JSON 数据 |
总结:
- Axios 是一个非常强大且易于使用的 HTTP 客户端,特别适用于需要发送异步请求的现代 Web 开发。它的 Promise 支持和拦截器功能,使得前端与后端的交互变得更高效、灵活。
- 与 jQuery 相比,Axios 在处理异步请求时更加现代化,并且对跨域请求、取消请求等功能提供了更多的支持。
- 如果你在进行现代 Web 开发,或者使用 React 、Vue 、Angular 等框架,Axios 是一个推荐的工具,它能够提供比传统的 jQuery 更强大的功能和更好的可维护性。
Fetch
随着axios被很多开发人员喜爱,后来现代化浏览器提供一个专门的API。fetch
是现代浏览器提供的一个 Web API,用于发送网络请求,获取资源。它提供了一种更简洁、灵活的方式来替代旧有的 XMLHttpRequest
(XHR) API,并且基于 Promise,使得处理异步操作更简单。
主要特点:
- 基于 Promise :
fetch
使用 Promise 作为返回值,允许使用.then()
和.catch()
进行链式处理。 - 简单直观 :语法简洁,相比
XMLHttpRequest
,fetch
更容易理解和使用。 - 支持异步操作:支持 GET、POST 等 HTTP 方法,适用于发送和接收 JSON、文本、二进制数据等。
- 更好的错误处理 :
fetch
本身不会自动处理 HTTP 错误状态码(如 404 或 500),但提供了更多的灵活性。
请看使用fetch获取数据的使用示例
js
fetch(url, options)
.then(response => {
if (!response.ok) { // 判断请求是否成功
throw new Error('Network response was not ok');
}
return response.json(); // 返回 JSON 格式的响应数据
})
.then(data => {
console.log(data); // 处理成功返回的数据
})
.catch(error => {
console.error('There has been a problem with your fetch operation:', error); // 处理错误
});
fetch对请求成功和失败都提供相应方法处理,使用起来非常方便。fetch同样支持post请求
下面是使用fetch的POST方式发送数据
js
fetch('https://api.example.com/submit', {
method: 'POST',
headers: {
'Content-Type': 'application/json', // 请求头,表示数据是 JSON 格式
},
body: JSON.stringify({
name: 'John Doe',
email: 'john.doe@example.com',
}), // 请求体,数据以 JSON 格式传送
})
.then(response => response.json()) // 解析 JSON 格式的响应
.then(data => console.log(data)) // 使用返回的数据
.catch(error => console.error('Error:', error));
发送带有认证的请求(例如 Authorization 头):
js
fetch('https://api.example.com/user', {
method: 'GET',
headers: {
'Authorization': 'Bearer YOUR_ACCESS_TOKEN', // 添加认证令牌
},
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Fetch error:', error));
fetch
本身并不直接提供超时控制,不过你可以通过 AbortController
来实现超时控制。
js
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 5000); // 5秒后超时
fetch('https://api.example.com/data', {
signal: controller.signal, // 传递信号对象
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => {
if (error.name === 'AbortError') {
console.log('Request timed out');
} else {
console.error('Fetch error:', error);
}
})
.finally(() => clearTimeout(timeoutId)); // 清除定时器
fetch
vs XMLHttpRequest
:
- 简洁性 :
fetch
API 使用 Promise,使得异步操作更易于处理和链式调用,相比传统的XMLHttpRequest
,代码更简洁。 - 支持的功能 :
fetch
支持更多的 HTTP 特性,例如跨域请求时的 CORS 支持、请求取消等。 - 浏览器支持 :现代浏览器(如 Chrome、Firefox、Edge)都支持
fetch
,但是在较老的浏览器中(如 IE),fetch
可能不被支持,可以通过 polyfill 来补充。
fetch
和XMLHttpRequest
是浏览器原生支持的请求方式,功能十分丰富,绝大部分场景下不需要引入第三方请求库,原生fetch可以满足项目需求
useRequest
当Vue/React流行后,社区中提出一些处理网络请求的新方法。比如ahooks提出的useRequest方法。
在useRequest中。认为页面同时只能是错误/数据/加载中其中一个状态,当请求发生时,页面中显示正在加载中的状态,当请求成功,则显示数据,当请求失败,则显示错误提示,页面的变化完全由状态驱动,用户体验有显著提升。
ahooks
是一个基于 React 的开源库,提供了一些常用的 React hooks,帮助开发者更高效地构建应用。useRequest
是 ahooks
中的一个非常常用的 hook,它主要用于处理异步请求,简化请求数据的管理、加载状态、错误处理等。
useRequest
的参数类型:
js
const { loading, data, error } = useRequest(fetchMethod, options)
第一个请求方法,第二个参数是配置对象,传入对应的配置项
useRequest
的基本功能:
- 发送请求 :可以用来发送 HTTP 请求(比如用
fetch
、axios
等)并返回请求的结果。 - 请求状态管理 :自动管理请求的加载状态(如
loading
、error
、data
等)。 - 缓存与重试:支持请求的缓存、重试等高级功能。
- 错误处理:自动处理请求中的错误状态。
useRequest
支持的功能很多,笔者只是举出基本功能,详细功能请看官方文档
请看useRequest
的官方使用示例
js
import { useRequest } from 'ahooks';
import Mock from 'mockjs';
import React from 'react';
function getUsername(): Promise<string> {
return new Promise((resolve) => {
setTimeout(() => {
resolve(Mock.mock('@name'));
}, 1000);
});
}
export default () => {
const { data, error, loading } = useRequest(getUsername);
if (error) {
return <div>failed to load</div>;
}
if (loading) {
return <div>loading...</div>;
}
return <div>Username: {data}</div>;
};
开发人员只需要关注useRequest返回的 error
、loading
和data
三个状态。开发人员只需要专注业务实现上
SWR
SWR跟ahooks的useRequest
本质上区别不大,SWR侧重Stale-While-Revalidate概念,useRequest只是ahooks中的一个方法,如果只想使用useRequest,没必要使用ahooks,可以使用SWR依赖。
SWR(Stale-While-Revalidate)是一个用于数据获取的 React 库,旨在通过缓存和后台重新验证的策略提供高效、简洁的数据请求管理。它是由 Vercel(Next.js 的开发团队)创建的,设计目标是简化在 React 应用中进行数据请求和缓存管理的过程。
设计原理
"SWR" 这个名字来自 stale-while-revalidate:一种由 HTTP RFC 5861 推广的 HTTP 缓存失效策略
这种策略首先从缓存中返回数据(过期的),同时发送 fetch 请求(重新验证),当返回数据的时候用最新的数据替换运行的数据。数据的请求和替换的过程都是异步的,对于用户来说无需等待新请求返回时就能看到数据
stale-while-revalidate
是 HTTP 的响应头 cache-control
的一个属性值,它允许立马返回一个已经过时 (stale) 的响应。与此同时浏览器又在背后默默重新发起一次请求,响应的结果被存储起来下次使用。因此它很好的隐藏了服务器或者网络的响应延时
为什么这里说允许返回一个 stale 的响应呢?如何判断响应是 stale 的呢,这是因为 stale-while-revalidate
是和 max-age
一起使用的,如果时间超过了 max-age
,则是作为 stale
shell
Cache-Control: max-age=600, stale-while-revalidate=30
- 表示请求的结果在 600s 内都是新鲜(stale 的反义词)的,如果在 600s 内发起了相同请求,则直接返回磁盘缓存
- 如果在 600s~630s 内发起了相同的请求,则响应虽然已经过时(stale)了,但是浏览器会直接把之前的缓存结果返回,与此同时浏览器又在背后自己发一个请求,响应结果留作下次使用
- 如果超过 630s 后,发起了相同请求,则这就是一个普通请求,就和第一次请求一样,从服务器获取响应结果,并且浏览器并把响应结果缓存起来
SWR 的主要功能有:
- 自动缓存:SWR 会自动缓存已请求的数据,以避免重复请求相同的数据,减少不必要的网络流量。
- 后台更新:当数据获取成功后,SWR 会自动在后台重新请求数据来更新缓存中的内容,从而确保数据的新鲜度。
- 自动重试机制:如果请求失败,SWR 会自动进行重试,直到请求成功为止(重试次数和间隔可以配置)。
- 增量更新和分页支持:SWR 可以很好地处理增量更新(例如,分页数据的加载)和并发请求,减少冗余操作。
- 简洁的 API:使用 SWR 只需要简单的 API 调用,不需要手动管理请求的状态(如 loading、error 等)。
下面是SWR的官网示例
js
import useSWR from 'swr'
function Profile() {
const { data, error, isLoading } = useSWR('/api/user', fetcher)
if (error) return <div>failed to load</div>
if (isLoading) return <div>loading...</div>
return <div>hello {data.name}!</div>
}
有关SWR更详细的分析,请看笔者的这篇文章深入浅出 SWR
React-Query
说完SWR就不得不提竞品React-Query,SWR支持的功能,React-Query全都支持,并且更强大。笔者没使用过React-Query,笔者只在这里简单描述一下
React Query 的核心功能包括:
- 数据获取(Fetching Data) :自动管理网络请求的生命周期,支持从远程 API 获取数据。
- 缓存(Caching) :缓存请求的数据,避免重复请求相同的数据,提升性能。
- 同步(Synchronization) :当数据变化时,React Query 会自动重新获取数据,确保应用的数据是最新的。
- 分页和懒加载(Pagination & Lazy Loading) :支持分页数据加载,避免一次性请求大量数据。
- 错误处理(Error Handling) :自动处理请求失败的情况,并提供机制来重试请求。
- 后台更新(Background Refetching) :可以在数据背景中定期刷新,确保数据是最新的。
- 依赖管理(Query Dependencies) :可以根据其他查询的结果来触发某些查询,管理复杂的依赖关系。
感兴趣的小伙伴可以去React Query官方文档学习使用
WebSocket
说到WebSocket,做过IM产品的小伙伴们肯定熟悉。
WebSocket 是一种在客户端和服务器之间进行全双工、持久化通信的协议。它提供了一种在单个 TCP 连接上进行双向通信的方式,这意味着客户端和服务器可以在任何时候相互发送数据,而无需重新建立连接。
所有图片来自即时通讯网
WebSocket的优点有如下几点:
- 较少的控制开销:在连接创建后,服务器和客户端之间交换数据时,用于协议控制的数据包头部相对较小;
- 更强的实时性:由于协议是全双工的,所以服务器可以随时主动给客户端下发数据。相对于 HTTP 请求需要等待客户端发起请求服务端才能响应,延迟明显更少;
- 保持连接状态:与 HTTP 不同的是,WebSocket 需要先创建连接,这就使得其成为一种有状态的协议,之后通信时可以省略部分状态信息;
- 更好的二进制支持:WebSocket 定义了二进制帧,相对 HTTP,可以更轻松地处理二进制内容;
- 可以支持扩展:WebSocket 定义了扩展,用户可以扩展协议、实现部分自定义的子协议。
脱离业务场景谈技术没有意义,WebSocket广泛地应用在即时通讯/IM、实时音视频、在线教育和游戏等领域。
那么在实际项目中如何使用WebSocket呢?对于简单的业务场景,可以直接使用原生的WebSocket
最基本的方式是直接使用浏览器的原生 WebSocket API,它内置在所有现代浏览器中。代码示例如下:
js
const socket = new WebSocket('ws://your-websocket-server.com');
// 连接建立时
socket.onopen = () => {
console.log('WebSocket is connected');
socket.send('Hello Server!');
};
// 接收消息时
socket.onmessage = (event) => {
console.log('Message from server:', event.data);
};
// 连接关闭时
socket.onclose = () => {
console.log('WebSocket connection closed');
};
// 连接出错时
socket.onerror = (error) => {
console.error('WebSocket error:', error);
};
如果不想使用原生WebSocket,可以使用第三方工具,比较受欢迎的是Socket.IO
Socket.IO
是一个非常流行的 WebSocket 库,提供了更高层次的 API,能自动处理 WebSocket 和其他传输协议的切换。它对于跨浏览器兼容性和实时功能非常有用。代码示例如下:
js
// 安装 Socket.IO 客户端
// npm install socket.io-client
import io from 'socket.io-client';
const socket = io('http://your-server.com');
socket.on('connect', () => {
console.log('Connected to server');
socket.emit('message', 'Hello Server!');
});
socket.on('message', (data) => {
console.log('Received message:', data);
});
socket.on('disconnect', () => {
console.log('Disconnected from server');
});
通过上面的例子可以看出项目接入WebSocket并不难
Server-Sent Events
实时获取服务端的数据,大家第一时间想到的是轮询和 WebSocket 两种方案,其实还有一种新方案 Server-sent events 下文简称(SSE)。SSE 中的数据只能由服务端推向客户端
SSE(Server-Sent Events)是一个基于 HTTP 协议的技术,用于在服务器端向客户端推送实时更新的数据。它允许服务器主动向浏览器发送信息,而不需要客户端不断向服务器发送请求。SSE 是一种单向通信(从服务器到客户端),并且是基于标准的 HTTP 协议的,因此可以在大多数现代浏览器中使用,而不需要额外的插件或复杂的设置。
SSE 的工作原理:
SSE 使用 HTTP 协议的长连接,允许服务器通过持久的连接向客户端发送数据。它的工作过程如下:
- 客户端请求 :客户端通过发送一个普通的 HTTP 请求来建立与服务器的连接,指定该请求是一个 SSE 连接(通常是通过设置
Accept: text/event-stream
请求头来告知服务器)。 - 服务器推送数据:服务器在建立连接后,通过该连接持续推送数据到客户端,而不是等待客户端发起新的请求。
- 客户端接收 :客户端通过 JavaScript 的
EventSource
API 接收从服务器推送的数据,并可以处理这些数据进行相应的操作。
主要特性:
- 单向通信:SSE 只允许从服务器到客户端的数据流动,不支持客户端向服务器发送数据(对于双向通信,可以使用 WebSocket)。
- 基于 HTTP:SSE 是基于标准的 HTTP 协议的,可以与现有的 HTTP 基础设施兼容,如负载均衡、代理等。
- 自动重连:如果连接断开,浏览器会自动尝试重新连接到服务器。
- 事件分离:SSE 可以发送多个事件,每个事件可以包含不同的数据,事件之间是分隔开的。
- 支持文本和数据流:通过 SSE,服务器可以向客户端发送文本格式的数据流,这些数据通常是 JSON 格式。
使用场景有
基于服务端单向的向客户端推送信息的特性,SSE 使用场景主要有
- Sass 平台的消息通知
- 信息流网站实时更新数据
笔者封装过一个简单的 sse-sdk 便于在项目中使用,代码如下
js
const defaultOptions = {
retry: 5,
interval: 3 * 1000,
};
class SSEClient {
constructor(url, options = defaultOptions) {
this.url = url;
this.es = null;
this.options = options;
this.retry = options.retry;
this.timer = null;
}
_onOpen() {
console.log("server sent event connect created");
}
_onMessage(handler) {
return (event) => {
this.retry = options.retry;
let payload;
try {
payload = JSON.parse(event.data);
console.log("receiving data...", payload);
} catch (error) {
console.error("failed to parse payload from server", error);
}
if (typeof handler === "function") {
handler(payload);
}
};
}
_onError(type, handler) {
return () => {
console.error("EventSource connection failed for subscribe.Retry");
if (this.es) {
this._removeAllEvent(type, handler);
this.unsubscribe();
}
if (this.retry > 0) {
this.timer = setTimeout(() => {
this.subscribe(type, handler);
}, this.options.interval);
} else {
this.retry--;
}
};
}
_removeAllEvent(type, handler) {
this.es.removeEventListener("open", this._onOpen);
this.es.removeEventListener(type, this._onMessage(handler));
this.es.removeEventListener("error", this._onError(type, handler));
}
subscribe(type, handler) {
this.es = new EventSource(url);
this.es.addEventListener("open", this._onOpen);
this.es.addEventListener(type, this._onMessage(handler));
this.es.addEventListener("error", this._onError(type, handler));
}
unsubscribe() {
if (this.es) {
this.es.close();
this.es = null;
}
if (this.timer) {
clearTimeout(this.timer);
}
}
}
使用方式如下所示
js
const sse = new SSEClient(url, options)
// 订阅
sse.subscribe()
// 取消订阅
sse.unsubscribe()
有关SSE更详细的使用和一些问题,请看笔者的这篇文章深入浅出 Server-sent events 技术
GraphQL
GraphQL 是一个用于 API 的查询语言,也是一个运行时环境,用于执行客户端请求的数据。这种技术由 Facebook 于 2012 年开发,并于 2015 年开源。与传统的 REST API 不同,GraphQL 提供了更加灵活和高效的方式来查询和操作数据。
前后端通过GraphQL通信需要后端创建GraphQL服务,前端使用GraphQL工具库与后端GraphQL服务建立连接。
常见的前端 GraphQL 客户端有:
- Apollo Client:功能强大,支持缓存、订阅等。
- Relay:Facebook 提供的一个高效的 GraphQL 客户端,适用于大型 React 应用。
- urql:一个轻量级的 GraphQL 客户端,适用于较小的应用或对性能要求较高的场景。
下面是使用Apollo Client的示例代码
js
import { useQuery, gql } from '@apollo/client';
const GET_USERS = gql`
query {
users {
id
name
email
}
}
`;
function UserList() {
const { loading, error, data } = useQuery(GET_USERS);
if (loading) return <p>Loading...</p>;
if (error) return <p>Error: {error.message}</p>;
return (
<ul>
{data.users.map(user => (
<li key={user.id}>{user.name} ({user.email})</li>
))}
</ul>
);
}
总结来说,前后端使用 GraphQL 需要后端准备好 GraphQL 服务(包括 schema、resolver、启动服务器等),前端使用合适的 GraphQL 客户端进行数据交互,双方需协调好认证、授权等安全措施,以及考虑到性能优化。
MQTT.js
MQTT.js 是一个客户端库,用于在 JavaScript 环境中实现 MQTT(Message Queuing Telemetry Transport)协议。MQTT 是一种轻量级的消息传递协议,广泛用于物联网(IoT)设备间的通信。通过 MQTT.js,你可以在浏览器、Node.js 或任何支持 JavaScript 的环境中使用 MQTT 协议进行消息发布和订阅。
主要特点:
- 支持发布(Publish)和订阅(Subscribe)功能。
- 支持 MQTT 3.1 和 3.1.1 标准。
- 可处理 QoS(Quality of Service)级别。
- 支持 WebSocket。
示例代码
下面是一个简单的 MQTT.js 使用示例,展示如何在 Node.js 环境下使用 MQTT.js 连接到 MQTT Broker,发布和订阅消息。
安装 MQTT.js
首先,确保你安装了 mqtt
包:
shell
npm install mqtt
发布消息的示例代码(Publisher)
js
// 引入 MQTT.js
const mqtt = require('mqtt');
// 连接到 MQTT broker
const client = mqtt.connect('mqtt://broker.hivemq.com');
// 连接成功后
client.on('connect', () => {
console.log('Connected to MQTT broker');
// 发布消息到 'test/topic' 主题
client.publish('test/topic', 'Hello from MQTT.js!', (err) => {
if (err) {
console.error('Publish failed:', err);
} else {
console.log('Message published');
}
});
// 断开连接
client.end();
});
// 处理错误
client.on('error', (err) => {
console.error('Connection error:', err);
});
订阅消息的示例代码(Subscriber)
js
// 引入 MQTT.js
const mqtt = require('mqtt');
// 连接到 MQTT broker
const client = mqtt.connect('mqtt://broker.hivemq.com');
// 连接成功后
client.on('connect', () => {
console.log('Connected to MQTT broker');
// 订阅 'test/topic' 主题
client.subscribe('test/topic', (err) => {
if (err) {
console.error('Subscription failed:', err);
} else {
console.log('Subscribed to topic');
}
});
});
// 处理接收到的消息
client.on('message', (topic, message) => {
console.log(`Received message: "${message.toString()}" on topic: ${topic}`);
});
// 处理错误
client.on('error', (err) => {
console.error('Connection error:', err);
});
运行
- 在一个终端中运行订阅代码(Subscriber)。
- 在另一个终端中运行发布代码(Publisher)。
当发布代码运行时,订阅代码会接收到发布的消息。
连接到 WebSocket Broker
如果你想通过 WebSocket 连接到 MQTT Broker,修改连接方式即可。例如,连接到一个 WebSocket 支持的 Broker:
ini
const client = mqtt.connect('ws://broker.hivemq.com:8000/mqtt');
关于 QoS(服务质量)
- QoS 0: 最多一次传输,消息可能丢失。
- QoS 1: 至少一次传输,确保消息传递,但可能会重复。
- QoS 2: 仅一次传输,确保消息不重复并成功传递。
在发布和订阅时,你可以通过设置 QoS 来控制消息传输的可靠性:
php
client.subscribe('test/topic', { qos: 1 });
client.publish('test/topic', 'Message with QoS 1', { qos: 1 });
这就是 MQTT.js 的一个简单应用示例。如果你有更复杂的需求,MQTT.js 还支持更多的功能,如消息重试、连接丢失的处理等。你可以参考官方文档:MQTT.js GitHub。
RPC
远程过程调用(RPC,Remote Procedure Call)是一种在计算机网络中进行通信的协议,它允许在不同计算机上运行的程序(通常是在不同主机上)像调用本地函数一样调用远程系统上的函数或方法。简单来说,RPC 让你能够通过网络调用另一台机器上的代码,就像它是在你本地机器上一样。
工作原理
- 调用过程:当你在本地代码中调用一个远程过程时,RPC 框架将该调用转化为网络请求,并通过网络传输到远程机器。
- 远程执行:远程机器接收到请求后,会在其本地系统上执行该过程/函数,处理数据。
- 返回结果:执行完成后,远程系统会把结果通过网络返回给调用方,调用方可以像本地函数调用一样使用该结果。
使用场景
- 分布式系统:在一个分布式系统中,RPC 允许各个服务之间进行远程通信。
- 微服务架构:在微服务架构中,服务之间的通信通常使用 RPC(如 gRPC)来传输消息和调用方法。
- 跨语言调用:RPC 协议通常支持多种语言,使得不同编程语言编写的服务可以互相调用。
在前端 React 项目中使用 RPC。常见的 RPC 协议有 gRPC 、JSON-RPC 、XML-RPC 等,前端 React 项目可以通过合适的工具和库来实现这些协议的调用。下面以gRPC给出示例简单说明要做哪些工作
- 设置 gRPC 后端
首先确保后端支持 gRPC,并且生成了 .proto
文件(Protobuf 格式)。这些文件用于定义服务和消息格式。
js
// greeter.proto
syntax = "proto3";
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply);
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 1;
}
- 安装 gRPC-web
在 React 项目中,你需要安装 grpc-web
和相关的工具。
shell
npm install grpc-web
npm install google-protobuf
- 生成 Protobuf 文件
使用 protoc
编译器来生成 JavaScript 客户端代码。首先需要安装 protoc
编译器,并确保你已经有了 .proto
文件。
运行以下命令来生成代码:
shell
protoc -I=. greeter.proto \
--js_out=import_style=commonjs,binary:./src/proto \
--grpc-web_out=import_style=typescript,mode=grpcwebtext:./src/proto
- 在 React 中使用 gRPC
在 React 中,你可以使用自动生成的客户端代码来调用 gRPC 服务。
js
import React, { useEffect, useState } from 'react';
import { GrpcWebClientBase } from 'grpc-web';
import { GreeterClient } from './proto/GreeterServiceClientPb'; // 生成的客户端代码
import { HelloRequest } from './proto/greeter_pb'; // 生成的消息类
const grpcClient = new GreeterClient('http://localhost:8080', null, null);
const App = () => {
const [message, setMessage] = useState('');
useEffect(() => {
const request = new HelloRequest();
request.setName('React User');
grpcClient.sayHello(request, {}, (err, response) => {
if (err) {
console.error('Error:', err);
} else {
setMessage(response.getMessage());
}
});
}, []);
return (
<div>
<h1>{message ? message : 'Loading...'}</h1>
</div>
);
};
export default App;
- 启动 gRPC-Web 代理
由于 gRPC 在浏览器中无法直接运行,你需要一个代理(例如 Envoy )来转发请求。你可以使用 envoy
来将 gRPC-web 请求代理到后端的 gRPC 服务。
想成功在项目中使用RPC,需要完成上面五个部署,笔者觉得非常繁琐,除非项目必须用到RPC通信,否则一般情况下考虑前后端使用HTTP通信
Navigator.sendBeacon
Navigator.sendBeacon()
是一个 Web API,用于在网页卸载或跳转之前异步地发送少量数据到服务器。它特别适用于那些需要确保数据被发送而不会阻塞页面加载或卸载的场景,例如分析、跟踪、日志记录等。
大家对于endBeacon可能比较陌生,那么与常规的 XMLHttpRequest
或 fetch()
有什么不同呢?sendBeacon()
是设计用来在页面卸载时仍能可靠地发送请求,即使用户关闭了网页或浏览器。它具有以下特点:
- 异步:发送数据的操作是非阻塞的,不会影响页面的加载或卸载过程。
- 简单:它支持发送小量的二进制或文本数据。
- 可靠性:即使页面在请求发送过程中关闭,数据仍然能被发送到服务器。
下面是sendBeacon的用法
js
navigator.sendBeacon(url, data);
url
:请求发送的目标 URL。data
:要发送的数据,通常是Blob
、FormData
、String
或ArrayBuffer
类型。
请看下面的使用示例
js
const url = "/log";
const data = JSON.stringify({ event: "page_view", timestamp: Date.now() });
navigator.sendBeacon(url, data);
这个代码片段会将页面查看事件和时间戳异步地发送到 /log
端点,即使用户正在关闭页面,数据仍然会被发送。
sendBeacon()
方法在处理一些需要发送日志或数据的后台任务时非常有用,特别是在用户关闭或跳转页面的情况下。
需要注意的是sendBeacon()
方法依旧有跨域问题,它主要用于页面卸载时仍能可靠地发送请求,即使用户关闭了网页或浏览器。这一点非常重要