写一个类ChatGPT应用,前后端数据交互有哪几种

对世界的态度,本质都是对自己的态度

大家好,我是「柒八九」。一个「专注于前端开发技术/RustAI应用知识分享」Coder

前言

最近,公司有一个AI项目,要做一个文档问答的AI产品。前端部分呢,还是「友好借鉴」ChatGPT。别问为什么,问就是要站在巨人的肩膀上进行「带有中国特色」的创新。而后端是接入我们团队的模型,我咨询过模型团队,也是基于开源模型做参数的微调,这个魔幻的世界真让人欲罢不能。这就是大概的业务背景。

针对前端部分,其实没啥可聊的,就是接入模型返回的数据然后进行展示处理。大家以为这就是一个简单到令人发指的功能时。有一个点却映入眼帘,如何才能实现类似ChatGPT结果展示效果(逐步输出结果,类似打字效果)。也就是在结果返回的时候,如何做打字效果。

此外,还有一个大背景就是,由于需求是可能要上传多个文件,并且模型那边的操作可能对文档解析有一定的难度。所以,在客户端发起请求时,可能投喂给模型的物料有点多,返回的结果的时间也会很长。也就是如果处理不当的话,在结果没返回之前或者一股脑把结果处理完再返回的话,前端会有一段很长的等待时间。

从上面的需求点和解决方案,我们不难看出,其实结果的展示(打字效果)不是一个难点,我们可以借助简单的库或者手搓一个打字效果都是可以的,而是数据的获取制约我们应用响应。

我们又可以按照数据的发起方是谁(客户端/服务端)

  1. 基于最原始的数据获取方式,客户端发起请求,服务端接入模型数据并返回,然后前端一股脑把所以结果都接入。
  2. 数据的发起方是服务端,然后在有合适的数据时,就将其发布给客户端,前端接收到数据后就进行结果的显示。此处我们可以按照流式将数据返回

所以,这又引起了另外一个问题,前后端数据交互我们应该采用何种方式。其实针对,后端主动发起数据的方式我们有很多方案

  • 长轮询(Long-Polling)
  • WebSockets
  • 服务器发送事件(Server-Sent Events,SSE)
  • WebRTC
  • WebTransport

那我们到底用哪种方式亦或者说它们都是个啥,都有啥优缺点。所以,今天我们来用一篇文章来讲讲它们直接的区别和联系。

好了,天不早了,干点正事哇。

alt

我们能所学到的知识点

  1. 长轮询(Long-Polling)
  2. WebSockets
  3. 服务器发送事件( SSE)
  4. WebTransport
  5. WebRTC
  6. 技术的限制
  7. 性能比较
  8. 适用场景

1. 长轮询(Long-Polling)

长轮询可以在浏览器上通过 HTTP 启用一种服务器-客户端消息传递方法。该技术通过普通的 XHR 请求模拟了服务器推送通信。与传统的轮询不同,其中客户端会在「固定的时间间隔内重复向服务器请求数据」,长轮询建立了一条连接到服务器的连接,该连接保持打开状态,直到有新数据可用为止。一旦服务器有了新信息,就会将响应发送给客户端,并关闭连接。

在接收到服务器的响应后,客户端立即发起新的请求,这个过程会重复进行。这种方法允许「更即时地更新数据,并减少不必要的网络流量和服务器负载」。然而,它仍然可能引入通信延迟,并且不如其他实时技术(如 WebSockets)高效。

function longPoll({
  fetch('http://front789.com/poll')
    .then(response => response.json())
    .then(data => {
        console.log("接收到的数据:", data);
        longPoll(); // 立即发起新的长轮询请求
    })
    .catch(error => {
        /**
        * 在正常情况下可能会出现错误,
        * 当连接超时或客户端离线时。
        * 出现错误时,我们会在一段延迟后重新启动轮询。
        */

        setTimeout(longPoll, 10000);
    });
}
longPoll(); // 初始化长轮询

长轮询解决了在网络平台上构建双向应用程序的问题,也就是我们经常用的模式- 「客户端发出请求,服务器响应」。这是通过颠覆请求-响应模型来实现的:

  1. 客户端服务器发送 GET 请求:与传统的 HTTP 请求不同,我们可以将其视为开放式的。它不是请求特定的响应,而是在准备好时请求任何响应。
  2. 请求时间设置: HTTP 超时可以使用 Keep-Alive 头进行调整。
    • 长轮询利用此功能,通过设置非常长或无限期的超时时间,使请求保持打开状态,即使服务器没有立即响应。
  3. 服务器响应:当服务器有要发送的内容时,它会使用响应关闭连接。
    • 返回的数据可以是新的 聊天消息体育比分突发新闻等。
  4. 客户端发送新的 GET 请求,循环重新开始。
alt

2. WebSockets

WebSockets[1] 是一种实时技术,可通过持久的单套接字(socket)连接在客户端和服务器之间实现「双向全双工通信」WebSockets 相对于传统的 HTTP,代表了一个重大进步,因为一旦建立连接,双方就可以「独立发送数据」,这使其非常适合需要低延迟和高频更新的场景。

WebSocket 技术由两个核心构建块组成:

  • WebSocket协议: WebSocket是建立在 TCP协议之上的一种 「应用层协议」。该协议旨在允许客户端和服务器 「实时通信」,从而在 Web 应用程序中实现高效且响应迅速的数据传输。
  • WebSocket API: WebSocket API 是一个编程接口,用于创建 WebSocket 连接并管理 Web 应用程序中客户端和服务器之间的数据交换。几乎所有现代浏览器都支持 WebSocket API alt

如何工作的

概括地说,使用 WebSockets 涉及三个主要步骤:

  1. 打开 WebSocket 连接
    • 建立 WebSocket 连接的过程称为 握手,由客户端和服务器之间的 HTTP 请求/响应交换组成。
  2. 通过 WebSockets 传输数据
    • 成功打开握手后,客户端和服务器可以通过持久 WebSocket 连接交换消息(帧)。 WebSocket 消息可能包含字符串(纯文本)或二进制数据。
  3. 关闭 WebSocket 连接。
    • 一旦持久的 WebSocket 连接达到其目的,它就可以终止;
    • 客户端和服务器都可以通过发送关闭消息来启动关闭握手。
alt
// 创建 `WebSocket` 连接
const socket = new WebSocket("ws://localhost:7899");

// 打开链接,并发送信息
socket.addEventListener("open", (event) => {
  socket.send("Hello Front789!");
});

// 监听来自服务端的数据
socket.addEventListener("message", (event) => {
  console.log("来自服务端的数据", event.data);
});
// 关闭链接
socket.onclose = function(e{
   console.log("关闭链接", e);
};

虽然 WebSocket API 的基础用法很容易,但在生产环境中却相当复杂。一个 socket 可能会断开连接,必须相应地重新创建。特别是检测连接是否仍然可用或不可用可能会非常棘手。通常,我们会添加一个 ping-and-pong[2] 心跳以确保打开的连接不会关闭。我们可以借助类似像 Socket.IO[3] 这样的库来处理重连的情况,需要时提供了以「长轮询」为回退方案。

想了解更多关于WebSocket可以参考The WebSocket API and protocol explained[4]


3. 服务器发送事件(SSE)

服务器发送事件(Server-Sent EventsSSE)提供了一种标准方法,通过 HTTP 将服务器数据推送到客户端。与 WebSockets 不同,SSE 专门设计用于「服务器到客户端的单向通信」,使其非常适用于实时信息的更新或者那些在不向服务器发送数据的情况下实时更新客户端的情况。

我们可以将服务器发送事件视为单个 HTTP 请求,其中后端不会立即发送整个主体,而是保持连接打开,并通过每次发送事件时发送单个行来逐步传输答复。

alt

SSE是一个由两个组件组成的标准:

  1. 浏览器中的 EventSource 接口,允许客户端订阅事件:它提供了一种通过抽象较低级别的连接和消息处理来订阅事件流的便捷方法。
  2. 事件流协议:描述服务器发送的事件必须遵循的标准纯文本格式,以便 EventSource 客户端理解和传播它们

在浏览器的客户端上,我们可以使用服务器端生成事件脚本的 URL 初始化一个 EventSource[5] 实例。

// 连接到服务器端事件流
const evtSource = new EventSource("https://front789.com/events");

// 处理通用消息事件
evtSource.onmessage = event => {
    if(event.data.trim() !== 'undefined'){
    const newData = event.data;
    // 数据追加
    setResponse((prevResponse) => prevResponse.concat(newData));
  } else{
    // 当从服务端接收到值为`undefined`的数据时,关闭链接
    setTempPrompt(''); 
    eventSource.close();
  }
};

WebSockets 不同,EventSource 在连接丢失时会自动重新连接。

在服务器端,我们的脚本必须将 Content-Type 标头设置为 text/event-stream,并根据 SSE 规范[6]格式化每条消息。这包括指定事件类型数据有效负载可选字段,如事件 ID

以下是使用Node.js Express处理SSE的示例:

import express from 'express';
const app = express();
const PORT = process.env.PORT || 7890;

const headers = {
    'Content-Type''text/event-stream',
    'Connection''keep-alive',
    'Cache-Control''no-cache'
}

app.get('/events', (req, res) => {
    res.writeHead(200, headers);

    const sendEvent = (data) => {
        // 所有数据都必须以'data:'开头
        const formattedData = `data: ${JSON.stringify(data)}\n\n`;
        res.write(formattedData);
    };

    // 每两秒发送一个事件
    const intervalId = setInterval(() => {
        const message = {
            timenew Date().toTimeString(),
            message'服务端产生的数据',
        };
        sendEvent(message);
    }, 2000);

    // 关闭轮询
    req.on('close', () => {
        clearInterval(intervalId);
        res.end();
    });
});
app.listen(PORT, () => console.log(`Server running on http://localhost:${PORT}`));

文章最开始,我们不是说想实现实时响应后端返回并且逐字显示聊天机器人回复,我们其实就可以使用SSE的方案。而ChatGPT也是使用这个机制实现的。


4. WebTransport

WebTransport[7] 是一个专为 Web 客户端和服务器之间进行高效、低延迟通信而设计的前沿 API。它利用了 HTTP/3 QUIC 协议[8],可以实现以可靠不可靠的方式实现多个流的数据传输功能,甚至允许数据无序发送。这使得 WebTransport 成为需要高性能网络的应用程序的强大工具,如实时游戏、直播和协作平台。但是,值得注意的是,WebTransport 目前是一个工作草案,尚未被广泛采用。 alt

截至目前(2024 年 5 月),WebTransport 仍处于工作草案阶段[9],并没有得到广泛支持。 alt

目前还不能在 Safari 浏览器中使用 WebTransport,而且 Node.js 也没有原生支持。这限制了其在不同平台和环境中的可用性。


5. WebRTC

网页实时通信(Web Real-time Communication,WebRTC)[10]是一个增强网页浏览模式。它允许浏览器通过安全访问输入设备(如网络摄像头麦克风),以「点对点的方式直接与其他浏览器交换实时媒体数据」

WebRTC 既是 API 又是协议。

  • WebRTC 协议是一组规则,供两个 WebRTC 代理协商双向安全实时通信。
  • WebRTC API 允许开发人员使用 WebRTC 协议。 WebRTC API 仅针对 JavaScript

传统的网页架构是基于客户端-服务器模型,客户端发送HTTP请求到服务器并获得包含所请求信息的响应。与此相对,WebRTC允许N个实体之间交换数据。在这种交换中,实体彼此直接通信,而无需中间服务器。

WebRTC内置于HTML 5,因此我们不需要第三方软件或插件即可使用它,我们可以通过WebRTC API在浏览器中访问它。它支持浏览器之间的音频视频和数据流交换的点对点连接。WebRTC 设计用于通过 NAT 和防火墙工作,利用诸如 ICESTUNTURN 等协议来建立对等之间的连接。

alt

虽然 WebRTC 是为客户端-客户端交互设计的,但也可以利用它进行服务器-客户端通信,其中「服务器只是模拟成一个客户端」。这种方法只适用于特定的用例,问题在于,要使 WebRTC 正常工作,我们仍然需要一个服务器,这个服务器会再次通过 WebSocketsSSEWebTransport 运行。这就背离了使用 WebRTC 作为这些技术的替代方案的初衷。


6. 技术的限制

双向发送数据

只有 WebSocketsWebTransport「双向全双工通信」,这样我们就可以在同一个连接上接收服务器数据并发送客户端数据。

虽然理论上使用长轮询也是可能的,但并不建议,因为向现有的长轮询连接发送“新”数据实际上还是需要额外的 HTTP 请求。因此,我们可以通过额外的 HTTP 请求直接将数据从客户端发送到服务器,而不会中断长轮询连接。

SSE不支持向服务器发送任何附加数据。我们只能进行初始请求,即使在原生的 EventSource API 中,默认情况下也无法在 HTTP 主体中发送类似 POST 的数据。相反,我们必须将所有数据放在 URL 参数中,这被认为是一种不安全的做法,因为凭据可能会泄漏到服务器日志、代理和缓存中。

每个域的 6 个请求限制

大多数现代浏览器允许「每个域最多六个连接」这限制了服务器-客户端消息传递方法的可用性。这六个连接的限制甚至在浏览器选项卡之间共享,因此当我们在多个选项卡中打开相同的页面时,它们必须彼此共享六个连接池。

虽然这个策略可以防止D-DOS 攻击,但当多个连接是为了处理合法的通信时,它可能会造成很大的问题。为了解决这个限制,我们必须使用 HTTP/2HTTP/3,其中浏览器为每个域只会打开一个连接,然后使用「多路复用」来通过单个连接传输所有数据。虽然这样可以给我们几乎无限量的并行连接,但有一个 SETTINGS_MAX_CONCURRENT_STREAMS[11] 设置,它限制了实际的连接数量。对于大多数配置,默认值为 100 个并发流。

在移动应用程序中不保持连接

AndroidiOS 等操作系统上运行的移动应用程序中,保持打开连接(例如 WebSockets 和其他连接)会带来很大的挑战。移动操作系统被设计为「在一段时间的不活动后自动将应用程序移至后台,从而有效关闭任何打开的连接」。这种行为是操作系统资源管理策略的一部分,旨在节省电池并优化性能。因此,我们通常依赖于移动推送通知作为一种高效可靠的方法,以将数据从服务器发送到客户端。推送通知允许服务器提醒应用程序有新数据到达,促使执行某个操作或更新,而无需保持持续的打开连接。


7. 性能比较

对于一些我们平时可能会用到的技术例如WebSocketsSSE长轮询WebTransport 我们可以从延迟、吞吐量、服务器负载和在不同条件下的可伸缩性的角度来比较。

延迟

  • WebSockets:由于其通过单个持久连接进行全双工通信,提供了最低的延迟。适用于实时应用程序,其中立即数据交换至关重要。
  • SSE:也提供了低延迟的服务器到客户端通信,但不能直接发送消息回服务器,需要额外的 HTTP 请求。
  • 长轮询:由于依赖于为每个数据传输 「建立新的 HTTP 连接」,因此产生较高的延迟,使其对实时更新不太有效。此外,当服务器希望在客户端仍在打开新连接的过程中发送事件时,可能会出现延迟显著较大的情况。
  • WebTransport:承诺提供类似于 WebSockets 的低延迟,同时利用 HTTP/3 协议进行更高效的多路复用和拥塞控制。

吞吐量

  • WebSockets:由于其持久连接,能够实现高吞吐量,但当客户端无法处理数据时,吞吐量可能会受到反压的影响, 反压 [12]是指客户端无法处理服务器发送的数据速度。
  • SSE:对于向客户端广播消息而言,效率高于 WebSockets,开销较小,因此在单向的服务器到客户端通信中可能会实现更高的吞吐量。
  • 长轮询:由于频繁打开和关闭连接的开销较大,通常提供较低的吞吐量,这会 「消耗更多的服务器资源」
  • WebTransport:支持单个连接内的双向和单向数据流的高吞吐量,性能优于需要多个流的场景下的 WebSockets

可伸缩性和服务器负载

  • WebSockets:维护大量 WebSocket 连接可能会显著增加服务器负载,可能影响具有许多用户的应用程序的可伸缩性。
  • SSE:对于主要需要来自服务器到客户端的更新的场景,更具可伸缩性,因为与 WebSockets 相比,它使用的连接开销更小,因为它使用的是常规的 HTTP 请求,而不是像 WebSockets 那样需要运行协议更新的请求。
  • 长轮询:由于频繁建立连接产生的高服务器负载,所以是最不可伸缩的,通常仅适用于作为 「后备机制」
  • WebTransport:设计为高度可伸缩,受益于 HTTP/3 在处理连接和流时的高效性,与 WebSocketsSSE 相比,可能减少服务器负载。

8. 适用场景

服务器-客户端通信技术的领域中,每种技术都有其独特的优势和适用用例。SSE是最简单的实现选项,利用与传统 Web 请求相同的 HTTP/S 协议,因此可以规避企业防火墙限制和其他可能出现的技术问题。它们很容易集成到 Node.js 和其他服务器框架中,因此非常适合需要频繁服务器到客户端更新的应用程序,如新闻源、股票行情和实时事件流。

另一方面,WebSockets 在需要持续的双向通信的场景中表现出色。它们支持连续互动的能力,使其成为浏览器游戏、聊天应用程序和实时体育更新的首选。

然而,WebTransport 虽然潜力巨大,但面临着采用挑战。它在包括 Node.js 在内的服务器框架中得到的支持不广泛,并且与 Safari 不兼容。此外,它对 HTTP/3 的依赖进一步限制了其即时适用性,因为许多 Web 服务器(如 nginx)只有实验性的 HTTP/3 支持。虽然在支持可靠和不可靠数据传输的未来应用程序中有所希望,但在大多数用例中,WebTransport 还不是一个可行的选择。

长轮询曾经是一种常见的技术,但由于其效率低下和频繁建立新的 HTTP 连接的高开销,现在已经大大过时。虽然它可以作为没有对 WebSocketsSSE 进行支持的环境的后备方案,但由于存在显著的性能限制,通常不建议使用。


后记

「分享是一种态度」

「全文完,既然看到这里了,如果觉得不错,随手点个赞和“在看”吧。」

alt

Reference

[1]

WebSockets: https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API

[2]

ping-and-pong: https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API/Writing_WebSocket_servers#pings_and_pongs_the_heartbeat_of_websockets

[3]

Socket.IO: https://socket.io/

[4]

The WebSocket API and protocol explained: https://ably.com/topic/websockets

[5]

EventSource: https://developer.mozilla.org/en-US/docs/Web/API/EventSource

[6]

SSE 规范: https://www.w3.org/TR/2012/WD-eventsource-20120426/

[7]

WebTransport: https://www.w3.org/TR/webtransport/

[8]

HTTP/3 QUIC 协议: https://en.wikipedia.org/wiki/HTTP/3

[9]

工作草案阶段: https://w3c.github.io/webtransport/

[10]

网页实时通信(Web Real-time Communication,WebRTC): https://webrtc.org/?hl=zh-cn

[11]

SETTINGS_MAX_CONCURRENT_STREAMS: https://www.rfc-editor.org/rfc/rfc7540#section-6.5.2

[12]

反压: https://chromestatus.com/feature/5189728691290112

本文由 mdnice 多平台发布

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/327883.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

论文阅读:Self-Consistency Improves Chain of Thought Reasoning in Language Models

思维链 prompt 与预训练的大型语言模型相结合,在复杂的推理任务上取得了令人鼓舞的结果。在本文中,作者提出了一种新的解码策略,即自我一致性(self-consistency),以取代思维链 prompt 中使用的 naive 贪婪解…

uniapp + vue3 使用axios

场景 uniapp自带的uni.request不太好用,也有可能是自己用axios用的太熟悉了,所以还是用axios趁手点,所以尝试在uniapp中使用axios。 操作 因为uniapp项目没有package.json,所以先在项目根目录下执行 npm init, 执行完毕后直接…

HTML哆啦A梦

目录 写在前面 HTML简介 完整代码 代码分析 系列推荐 写在最后 写在前面 谁不想拥有一只可爱的叮当猫呢?本期小编给大家带来了一个萌萌的哆啦A梦。 HTML简介 HTML,即超文本标记语言,是构建网页的基础技术之一,它是一种标…

03-数据结构(一)

链接:C# 数据结构_哔哩哔哩_bilibili https://www.bilibili.com/video/BV1a541147Nk/?spm_id_from333.337.search-card.all.click&vd_source6eb7d966aa03ff5cb02b63725f651e68 链接:使用 C#.Net 学习掌握数据结构 (更新中)_哔哩哔哩_bilibili 一…

《Python编程从入门到实践》day28

# 昨日知识点回顾 安装Matplotlib 绘制简单的折线图 # 今日知识点学习 15.2.1 修改标签文字和线条粗细 # module backend_interagg has no attribute FigureCanvas. Did you mean: FigureCanvasAgg? # 解决办法:matplotlib切换图形界面显示终端TkAgg。 #…

.NET 一款团队内部免杀的WebShell

01本文概要 在.NET应用程序中,有时需要执行一些与系统相关的操作,例如调用Windows API函数来实现特定功能。本示例展示了如何在.NET页面中调用名为zipfldr.dll的动态链接库DLL中的RouteTheCall函数。 02函数及代码示例 zipfldr.dll是Windows操作系统中…

每日一题12:Pandas:数据重塑-融合

一、每日一题 解答: import pandas as pddef meltTable(report: pd.DataFrame) -> pd.DataFrame:reshaped_report report.melt(id_varsproduct, var_namequarter, value_namesales)return reshaped_report 题源:Leetcode 二、总结 melt()函数是Pa…

ctfshow parse_url wp

第一关 这个parse_url函数就是解析URL并且进行拆分的 $url "https://www.example.com/path/to/page?param1value1&param2value2";$parsed_url parse_url($url);print_r($parsed_url); Array ([scheme] > https[host] > www.example.com[path] > /p…

智慧安防系统:构建更安全的社区环境

随着科技的不断进步,人们的生活质量得到了显著提高。然而,与此同时,社会治安问题也日益凸显。为了维护社会的和谐稳定,提高人们的生活安全感,智慧安防系统应运而生。本文将为您详细介绍智慧安防系统的项目背景、需求分…

第十六节:图 (20节)

一 图的概念 1)由点的集合和边的集合构成 2)虽然存在有向图和无向图的概念,但实际上都可以用有向图来表达 3)边上可能带有权值 二 图结构的表达 1)邻接表法 2)邻接矩阵法 3)除此之外还有其他众多…

【Mac】如何解决打开PD虚拟机后Mac无法上网的问题?

问题描述 部分用户在运行Parallels Desktop并打开Windows 11后,发现Windows上网没有问题,但是Mac主机不能访问带域名的网站,而访问带IP的网站没问题,退出Parallels虚拟机以后,Mac网络又恢复正常。 解决办法 退出 Pa…

DC-DC直流升压线性可调电源模块电压控制输出0-50V/0-80V/0-100V/0-200V/0-250V/0-300V/0-500V/0-1000V

特点 效率高达 75%以上1*2英寸标准封装单电压输出可直接焊在PCB 上工作温度: -40℃~75℃阻燃封装,满足UL94-V0 要求温度特性好电压控制输出,输出电压随控制电压线性变化 应用 GRB 系列模块电源是一种DC-DC升压变换器。该模块电源的输入电压分为:4.5~9V、…

通配符SSL证书免费领取!不限量!

通配符SSL证书(泛域名证书)可以为主域名及其所有子域名提供安全保护,而无需为每个子域名单独申请证书。这对于拥有多个子域名的网站来说,极大地简化了管理和部署SSL证书的过程。 对于学习、测试或者前期预算不足的用户来说&#…

酷开科技依托酷开系统“硬件+内容”产业布局,抢占全球机遇!

2024年3月26日,创维集团发布了2023年年度业绩报告,去年全年实现了总营业额690.31亿元较上一年的534.91亿元整体营业额增长了29.1%。然而,值得注意的是,2023年度,创维集团智能家电业务的营收306.37亿元,较上…

Python轻量级Web框架Flask(14)—— 自己做Flask项目总结

0、前言: 本文意在记录自己在做毕业Flask项目开发时遇到的一些问题,并将问题解决方案记录下来,可做日后查询本文也会记录自己做FLask项目时实现的一些功能,作为开发工作的进程记录注意:用Flask开发的前提是已经设计好…

【js逆向】易车网JS逆向案例实战手把手教学(附完整代码)

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全…

Flask Web开发:使用render_template渲染动态HTML模板

文章目录 Flask简介render_template函数参数说明示例代码 模板文件结果展示 在Web开发中,经常需要将动态数据与HTML模板结合,以生成具有用户特定信息的网页。Python的Flask框架提供了一个功能强大的 render_template函数,用于实现这一目标。…

只用了三天就入门了Vue3?

"真的我学Vue3,只是为了完成JAVA课设" 环境配置 使用Vue3要去先下载Node.js。 就像用Python离不开pip包管理器一样。 Node.js — Run JavaScript Everywhere (nodejs.org) 下完Node.js去学习怎么使用npm包管理器,放心你只需要学一些基础的…

【opencv】opencv透视变换和ocr识别实验

实验环境:anaconda、jupyter notebook 实验用到的包opencv、numpy、matplotlib、tesseract 一、opencv透视变换 原图 图片是我拍的耳机说明书,哈哈哈哈,你也可以使用自己拍的照片,最好是英文内容,tesseract默认识别英…

洛谷 P3372:线段树 1 ← 分块算法模板(区间更新、区间查询)

【题目来源】https://www.luogu.com.cn/problem/P3372【题目描述】 如题,已知一个数列,你需要进行下面两种操作: (1)将某区间每一个数加上 k。 (2)求出某区间每一个数的和。【输入格式】 第一行…