HTTP/2 服务器端推送:FastAPI实现与前端集成指南
HTTP/2 服务器端推送:FastAPI实现与前端集成指南
注意:本文末尾附有完整示例代码,文中仅展示核心关键代码。完整代码可在GitHub仓库获取。
本文将会讲解HTTP2协议和相关配置实践。但是不要混淆,SSE的实现完全基于HTTP/1.1的持久连接机制,通过长连接实现实时数据推送。尽管HTTP/2的服务端推送也能主动发送数据,但其设计目标和应用场景与SSE不同,两者属于互补而非替代关系。若需实现服务端到客户端的单向实时通信,SSE仍是更轻量且兼容性更优的方案。
文章目录
- HTTP/2 服务器端推送:FastAPI实现与前端集成指南
- 一、HTTP协议的演进与HTTP/2的革命性变化
- 1.1 HTTP协议的发展历程
- 1.2 HTTP/2的核心特性
- 1.3 HTTP/2服务器推送的核心原理
- 二、FastAPI + Hypercorn实现HTTP/2推送
- 环境准备
- 后端代码示例
- 三、前端通信技术实现
- 1. 使用Fetch API获取数据
- 2. 使用EventSource接收服务器事件
- 3. 使用Fetch API实现SSE推送
- 3.1 Fetch API实现SSE的优势
- 3.2 Fetch API实现SSE的核心代码
- 3.3 实际应用:聊天机器人示例
- 四、技术对比与选择指南
- HTTP/2推送与其他实时通信技术对比
- 选择建议
- 五、最佳实践与注意事项
- 服务器推送最佳实践
- Fetch API实现SSE的最佳实践
- 六、总结与展望
一、HTTP协议的演进与HTTP/2的革命性变化
1.1 HTTP协议的发展历程
从互联网诞生至今,HTTP协议经历了几次重要演进:
- HTTP/0.9(1991年):最初的简单版本,只支持GET方法和HTML文档传输
- HTTP/1.0(1996年):引入了请求头/响应头、状态码、内容类型等基础概念
- HTTP/1.1(1997年):添加了持久连接、管道化请求、主机头等改进,成为互联网主流标准近20年
- HTTP/2(2015年):基于Google的SPDY协议,从文本协议转向二进制协议,解决了HTTP/1.1的性能瓶颈
- HTTP/3(进行中):基于QUIC协议,使用UDP替代TCP,进一步提升性能和可靠性
随着Web应用日益复杂,HTTP/1.1的局限性日益凸显:单个TCP连接的请求阻塞(队头阻塞)、冗余的请求头、低效的资源获取方式等,这些都导致了页面加载速度慢、用户体验差的问题。
1.2 HTTP/2的核心特性
HTTP/2在保持HTTP语义不变的前提下,从底层彻底重构了传输方式,引入了多项革命性特性:
- 二进制分帧层:将HTTP消息分解为更小的帧,实现更高效的解析和传输
- 多路复用:在单个TCP连接上并行处理多个请求/响应,消除了队头阻塞问题
- 头部压缩(HPACK):大幅减少HTTP头部大小,节省带宽
- 流优先级:允许客户端为请求设置优先级,优化资源加载顺序
- 服务器推送:允许服务器主动推送资源,无需客户端明确请求
1.3 HTTP/2服务器推送的核心原理
HTTP/2的服务器推送(Server Push)是一项革命性技术,允许服务器在客户端明确请求前主动推送资源,通过减少往返请求(RTT)显著提升页面加载速度。其核心流程包括:
- 推送触发:当客户端请求主资源(如
index.html
)时,服务器分析关联资源(如CSS/JS)并主动推送; - 帧层协议:通过
PUSH_PROMISE
二进制帧通知客户端即将推送的资源路径; - 缓存协商:浏览器根据缓存状态决定接受或拒绝推送资源(如已缓存则忽略)。
服务器推送解决了传统"瀑布式"资源加载的延迟问题,特别适合预加载首屏渲染所需的关键CSS和JavaScript资源,大幅提升用户感知性能。
二、FastAPI + Hypercorn实现HTTP/2推送
环境准备
- 安装依赖:需使用支持HTTP/2的ASGI服务器Hypercorn:
pip install fastapi hypercorn cryptography
- 生成SSL证书(HTTP/2强制加密):
为什么HTTP/2需要SSL证书? HTTP/2协议规范虽然不强制要求加密,但几乎所有浏览器实现都要求HTTP/2必须基于TLS(HTTPS)运行。这是因为加密不仅提供了安全性,还解决了中间设备干扰问题,确保HTTP/2的高级特性能够正常工作。
Linux/Mac环境使用OpenSSL命令:
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes
Windows环境可能没有OpenSSL命令,可以使用我们仓库中的Python脚本:
# 首先确保已安装cryptography库
pip install cryptography# 然后运行证书生成脚本
python generate_cert.py
这个脚本会自动生成自签名的SSL证书和私钥文件,适用于本地开发测试。脚本内容如下:
# generate_cert.py 的核心代码片段
from cryptography import x509
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.primitives import serialization
import datetime# 生成私钥
private_key = rsa.generate_private_key(public_exponent=65537,key_size=4096,
)# 生成自签名证书
cert = x509.CertificateBuilder()....sign(private_key, hashes.SHA256())# 将私钥和证书写入文件
with open("key.pem", "wb") as f:f.write(private_key.private_bytes(...))with open("cert.pem", "wb") as f:f.write(cert.public_bytes(...))
注意:自签名证书会导致浏览器显示安全警告,这在开发环境中是正常的,可以在高级选项中选择继续访问。生产环境应使用受信任的CA颁发的证书。
后端代码示例
创建一个名为http2_server.py
的文件:
from fastapi import FastAPI, Response, Request
from fastapi.responses import HTMLResponse, StreamingResponse
from fastapi.staticfiles import StaticFiles
from hypercorn.config import Config
from hypercorn.asyncio import serve
import asyncio
import osapp = FastAPI()# 静态文件目录配置(可选)
if not os.path.exists("static"):os.makedirs("static")# 创建CSS文件with open("static/style.css", "w") as f:f.write("body { font-family: Arial; color: #333; background-color: #f5f5f5; }\n")f.write(".container { max-width: 800px; margin: 0 auto; padding: 20px; }\n")f.write("h1 { color: #0066cc; }\n")f.write(".card { background: white; border-radius: 8px; padding: 15px; margin: 15px 0; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }\n")# 创建JS文件with open("static/app.js", "w") as f:f.write("console.log('HTTP/2 Server Push Demo')\n")f.write("document.addEventListener('DOMContentLoaded', () => {\n")f.write(" const timeElement = document.getElementById('load-time')\n")f.write(" if (timeElement) {\n")f.write(" timeElement.textContent = `页面加载完成时间: ${new Date().toLocaleTimeString()}`\n")f.write(" }\n")f.write("})\n")app.mount("/static", StaticFiles(directory="static"), name="static")# 主页面请求触发资源推送
@app.get("/", response_class=HTMLResponse)
async def index(request: Request):html_content = """<!DOCTYPE html><html><head><title>HTTP/2 Server Push Demo</title><link rel="stylesheet" href="/static/style.css"><script src="/static/app.js"></script></head><body><div class="container"><h1>HTTP/2 服务器推送演示</h1><div class="card"><p>这个页面使用HTTP/2服务器推送技术预加载了CSS和JavaScript资源。</p><p>打开开发者工具的Network标签查看推送资源。</p><p id="load-time"></p></div><div class="card"><h2>测试链接</h2><ul><li><a href="/fetch-demo">Fetch API示例</a></li><li><a href="/sse-demo">EventSource (SSE)示例</a></li><li><a href="/fetch-sse-chatbot">Fetch API实现SSE聊天机器人</a></li></ul></div></div></body></html>"""# 设置Link头以触发HTTP/2服务器推送response = HTMLResponse(content=html_content)response.headers["Link"] = "</static/style.css>; rel=preload; as=style, </static/app.js>; rel=preload; as=script"return response# Fetch API示例页面
@app.get("/fetch-demo", response_class=HTMLResponse)
async def fetch_demo():return HTMLResponse(content="""...""") # 省略内容# SSE (EventSource) 示例页面
@app.get("/sse-demo", response_class=HTMLResponse)
async def sse_demo():return HTMLResponse(content="""...""") # 省略内容# Fetch API实现SSE聊天机器人示例
@app.get("/fetch-sse-chatbot", response_class=HTMLResponse)
async def fetch_sse_chatbot():# 返回聊天机器人HTML页面with open("static/fetch-sse-chatbot.html", "r") as f:content = f.read()return HTMLResponse(content=content)# API端点 - 用于Fetch示例
@app.get("/api/data")
async def get_data():# 模拟API数据return {"message": "HTTP/2通信成功","timestamp": asyncio.get_event_loop().time(),"items": ["项目1", "项目2", "项目3"],"status": "success"}# SSE端点 - 用于EventSource示例
@app.get("/api/events")
async def event_stream():async def generate():for i in range(1, 16):# SSE格式: 每条消息以data:开头,以两个换行结束yield f"data: 消息 #{i} - 时间: {asyncio.get_event_loop().time():.2f}\n\n"await asyncio.sleep(1)return StreamingResponse(generate(), media_type="text/event-stream")# 聊天机器人消息处理API
@app.post("/api/chat")
async def chat(request: Request):data = await request.json()message = data.get("message", "")# 这里可以添加实际的聊天机器人逻辑return {"status": "received"}# 聊天机器人SSE流API
@app.get("/api/chat-stream")
async def chat_stream():async def generate():# 模拟聊天机器人响应responses = ["你好!我能帮你什么忙?","我是一个基于HTTP/2和Fetch API实现的SSE聊天机器人。","你可以问我关于HTTP/2、SSE或Fetch API的问题。","与传统EventSource相比,使用Fetch API实现SSE有更多的灵活性。"]for response in responses:# 模拟思考时间await asyncio.sleep(1)yield f"data: {response}\n\n"return StreamingResponse(generate(), media_type="text/event-stream")# 启动HTTP/2服务器
if __name__ == "__main__":config = Config()config.bind = ["0.0.0.0:8000"]config.keyfile = "key.pem"config.certfile = "cert.pem"config.http2 = Trueprint("启动HTTP/2服务器在 https://localhost:8000")print("注意: 由于使用自签名证书,浏览器可能会显示安全警告,可以选择继续访问。")asyncio.run(serve(app, config))
关键点说明:
- 通过
Link
头声明预加载资源,触发服务器推送逻辑 - Hypercorn的HTTP/2模式需配合SSL证书启动
- 静态资源(CSS/JS)通过服务器推送提前发送给客户端
- 提供了两种前端通信方式的示例:Fetch API和EventSource (SSE)
我们打开https://localhost:8001/ ,页面如下:
三、前端通信技术实现
1. 使用Fetch API获取数据
Fetch API是现代浏览器提供的用于网络请求的接口,在HTTP/2环境中性能更佳:
async function fetchData() {try {const response = await fetch('/api/data');const data = await response.json();document.getElementById('result').textContent = JSON.stringify(data, null, 2);} catch (error) {console.error('获取数据失败:', error);}
}
HTTP/2优势:
- 多路复用:同一连接可并行处理多个请求,无需建立多个TCP连接
- 头部压缩:减少请求头大小,节省带宽
- 二进制传输:更高效的数据传输格式
2. 使用EventSource接收服务器事件
EventSource API(也称为Server-Sent Events,SSE)提供了从服务器接收实时更新的标准方式:
const eventSource = new EventSource('/api/events');eventSource.onmessage = function(event) {console.log('收到消息:', event.data);// 处理接收到的数据
};eventSource.onerror = function() {console.error('EventSource连接错误');
};// 不再需要时关闭连接
// eventSource.close();
与WebSocket对比:
- EventSource是单向通信(服务器到客户端),WebSocket是双向通信
- EventSource基于HTTP协议,自动重连,实现更简单
- EventSource在HTTP/2上运行效率更高,共享连接复用特性
3. 使用Fetch API实现SSE推送
虽然浏览器提供了原生的EventSource API用于SSE,但使用Fetch API实现SSE具有更多优势和灵活性:
3.1 Fetch API实现SSE的优势
- 更灵活的请求控制:可添加自定义头部、凭证、跨域设置等
- 可中断连接:通过AbortController可以优雅地中断连接
- 更好的错误处理:提供更详细的错误信息和重试机制
- 与其他Fetch请求共享HTTP/2连接复用优势
- 不受同源策略的默认限制:可以通过CORS配置访问跨域资源
3.2 Fetch API实现SSE的核心代码
以下是使用Fetch API实现SSE的核心代码片段:
async function startSSEConnection() {try {// 创建AbortController用于中断连接const controller = new AbortController();const signal = controller.signal;// 使用fetch获取事件流const response = await fetch('/api/chat-stream', {signal,headers: {'Accept': 'text/event-stream'}});// 获取响应的可读流const reader = response.body.getReader();const decoder = new TextDecoder();let buffer = '';// 处理数据流while (true) {const { done, value } = await reader.read();if (done) break;// 解码并添加到缓冲区buffer += decoder.decode(value, { stream: true });// 处理SSE格式的消息const messages = buffer.split('\n\n');buffer = messages.pop(); // 保留最后一个可能不完整的消息for (const message of messages) {if (message.startsWith('data: ')) {const data = message.substring(6); // 去掉'data: 'console.log('收到消息:', data);// 处理接收到的数据}}}} catch (error) {if (error.name === 'AbortError') {console.log('连接已中断');} else {console.error('SSE连接错误:', error);}}
}
3.3 实际应用:聊天机器人示例
我们创建了一个使用Fetch API实现SSE的聊天机器人示例,完整代码可在static/fetch-sse-chatbot.html
中找到。以下是关键实现部分:
// 使用Fetch API实现SSE连接
async function startSSEConnection() {try {// 如果已有连接,先中断if (controller) {controller.abort();}// 创建新的AbortController用于中断连接controller = new AbortController();const signal = controller.signal;// 使用fetch获取事件流const response = await fetch('/api/chat-stream', {signal,headers: {'Accept': 'text/event-stream'}});// 获取响应的可读流并处理const reader = response.body.getReader();const decoder = new TextDecoder();let buffer = '';// 循环读取数据流while (true) {const { done, value } = await reader.read();if (done) break;// 解码并处理SSE格式消息buffer += decoder.decode(value, { stream: true });const messages = buffer.split('\n\n');buffer = messages.pop();for (const message of messages) {if (message.startsWith('data: ')) {const data = message.substring(6);addMessage(data, false); // 显示机器人消息}}}} catch (error) {// 错误处理和自动重连逻辑if (error.name !== 'AbortError') {setTimeout(() => startSSEConnection(), 5000);}}
}
这个实现具有以下特点:
- 连接管理:使用AbortController管理连接状态,支持中断和重新连接
- 流式处理:使用ReadableStream API逐块处理数据,避免内存占用过大
- 错误恢复:实现了自动重连机制,提高了连接稳定性
- 消息解析:正确处理SSE格式的消息,支持分块接收和解析
. 推送拒绝场景:
- 若资源已缓存,浏览器会发送
RST_STREAM
帧拒绝推送 - 测试时可清除浏览器缓存(Chrome开发者工具 → Application → Clear Storage)
四、技术对比与选择指南
HTTP/2推送与其他实时通信技术对比
技术 | 适用场景 | 优势 | 劣势 |
---|---|---|---|
HTTP/2推送 | 静态资源预加载 | 减少RTT、提升首屏加载速度 | 不适合动态内容、可能浪费带宽 |
EventSource (SSE) | 服务器到客户端的实时数据流 | 简单实现、自动重连 | 单向通信、有连接数限制 |
WebSocket | 双向实时通信 | 全双工通信、低延迟 | 实现复杂、需要专门的服务器支持 |
HTTP长轮询 | 低频率更新 | 兼容性好、实现简单 | 服务器资源占用高、延迟大 |
Fetch API实现SSE | 需要灵活控制的服务器推送 | 自定义能力强、可中断、错误处理更好 | 实现稍复杂、需要手动解析消息 |
选择建议
- HTTP/2推送:适用于静态资源预加载,如CSS、JS、关键图片等
- EventSource:适用于简单的服务器推送场景,如通知、状态更新等
- WebSocket:适用于聊天应用、协作编辑、游戏等需要双向低延迟通信的场景
- Fetch API实现SSE:适用于需要更多控制能力的服务器推送场景,如需要自定义头部、认证、中断控制等
五、最佳实践与注意事项
服务器推送最佳实践
-
选择性推送:
- 只推送关键渲染路径资源(CSS、关键JS)
- 避免推送可能已缓存的资源
- 考虑使用Cookie或其他机制判断客户端是否需要推送
-
推送优先级:
- 首先推送CSS等阻塞渲染的资源
- 其次推送首屏所需的JS
- 最后推送图片等非关键资源
-
缓存控制:
- 为推送资源设置适当的Cache-Control头
- 利用ETag和条件请求避免重复推送
Fetch API实现SSE的最佳实践
-
连接管理:
- 使用AbortController管理连接生命周期
- 实现自动重连机制,处理网络波动
- 在组件卸载时正确关闭连接,避免内存泄漏
-
数据处理:
- 使用TextDecoder正确处理UTF-8编码
- 维护缓冲区处理分块接收的消息
- 考虑使用Web Workers处理大量数据,避免阻塞主线程
-
错误处理:
- 区分不同类型的错误(网络错误、服务器错误、中断等)
- 实现指数退避重试策略
- 提供用户友好的错误提示和恢复选项
但是也要注意避免过度推送的问题。
六、总结与展望
HTTP/2服务器推送是提升Web应用性能的强大工具,特别适合预加载静态资源。通过FastAPI和Hypercorn,Python开发者可以轻松实现HTTP/2服务器推送功能,结合现代前端技术如Fetch API和EventSource,构建高性能的Web应用。
使用Fetch API实现SSE为开发者提供了比传统EventSource更灵活的选择,特别适合需要更多控制能力的场景。这种方法充分利用了HTTP/2的多路复用特性,在保持简单性的同时提供了更强的可定制性。
虽然HTTP/2推送在某些场景下效果显著,但也需要注意其局限性,合理选择推送资源,避免过度使用。随着HTTP/3的发展,基于QUIC协议的新一代Web通信技术将继续改善性能和可靠性,值得持续关注。
参考资源:
- FastAPI官方文档
- Hypercorn文档
- HTTP/2规范
- MDN Web文档:Server-sent events
- MDN Web文档:Fetch API
**完整示例代码(新)**可在GitHub仓库获取。
相关文章:
HTTP/2 服务器端推送:FastAPI实现与前端集成指南
HTTP/2 服务器端推送:FastAPI实现与前端集成指南 注意:本文末尾附有完整示例代码,文中仅展示核心关键代码。完整代码可在GitHub仓库获取。 本文将会讲解HTTP2协议和相关配置实践。但是不要混淆,SSE的实现完全基于HTTP/1.1的持久连…...
C++ 变量的输入输出教程
一、变量的基本概念 在 C 中,变量是用于存储数据的命名内存位置。在使用变量之前,需要先声明它的类型和名称,这样编译器才能为其分配适当大小的内存空间。例如: int age; // 声明一个整型变量 age double salary; // 声明一个…...
java作业
java作业 一. package shiyanbaogao; import java.util.Scanner; //给20块钱买可乐,每瓶可乐3块钱,喝完之后退瓶子可以换回1块钱,问最多可以喝到多少瓶可乐。请设计相应的Java程序。 public class BaoGaoDemo02 {public static void …...
LeeCode题库第四十题
40.组合总和II 项目场景: 给定一个候选人编号的集合 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。 candidates 中的每个数字在每个组合中只能使用 一次 。 注意:解集不能包含重复的组合。 示…...
list的模拟实现
目录 一、构造和扩容机制 二、普通迭代器 三、const迭代器 四、tip 有了前面vetcor的基础呢,我们在学习和使用list上就更加的方便快捷,浅显易懂了,所以相似的部分我就不做过多的言语阐述了,在使用方面呢,大家可以学…...
pandas DataFrame 数据筛选与排序
数据筛选: df[df[列标签] > xxx] 使用 &(与) |(或) 拼接多个条件代码应用: &(与)应用 # 引用 pandas import pandas as pd # 定义数据 data {"产品":["男装","女装","男鞋","女鞋"…...
elpis全栈课程学习之elpis-core学习总结
elpis全栈课程学习之elpis-core学习总结 核心原理 elpis-core是全栈框架elpis的服务端内核,主要应用于服务端接口的开发以及页面的SSR渲染,elpis-core基于约定优于配置的原理,通过一系列的loader来加载对应的文件,大大节约用户的…...
零基础deep seek+剪映,如何制作高品质的视频短片
以下是专为零基础学习者设计的 剪映专业版详细教程+Deep seek配合制 ,包含从入门到精通的系统化教学,配合具体操作步骤与实用技巧: 基于DeepSeek与剪映协同制作高品质视频短片的专业流程指南(2025年最新实践版&#x…...
解决单元测试 mock final类报错
文章目录 前言解决单元测试 mock final类报错1. 报错原因2. 解决方案3. 示例demo4. 扩展 前言 如果您觉得有用的话,记得给博主点个赞,评论,收藏一键三连啊,写作不易啊^ _ ^。 而且听说点赞的人每天的运气都不会太差࿰…...
Git基本命令索引
GIT基本命令索引 创建代码库修改和提交代码日志管理远程操作操作分支 创建代码库 操作指令初始化仓库git init克隆远程仓库git clone 修改和提交代码 操作指令查看文件状态git status文件暂存git add文件比较git diff文件提交git commit回滚版本git reset重命名或者移动工作…...
非平稳时间序列分析(二)——ARIMA(p, d, q)模型
此前篇章(平稳序列): 时间序列分析(一)——基础概念篇 时间序列分析(二)——平稳性检验 时间序列分析(三)——白噪声检验 时间序列分析(四)—…...
[代码规范]接口设计规范
一个优雅的接口要如何设计?有哪些设计规范可以遵循? 下面抛砖引玉,分享一些规范。 目录 1、RESTful API 设计最佳实践 2、Shneiderman 的 8 条黄金法则 3、Nielsen 的 10 条启发式规则 1、RESTful API 设计最佳实践 一共18条,参考…...
4-3自定义加载器,并添加功能
一、自定义类加载器的实现步骤 继承ClassLoader类 自定义类加载器需继承java.lang.ClassLoader,并选择性地重写以下方法: findClass(String name):核心方法,用于根据类名查找并加载类的字节码。需从自定义路径(…...
北京大学DeepSeek提示词工程与落地场景(PDF无套路免费下载)
近年来,大模型技术飞速发展,但许多用户发现:即使使用同一款 AI 工具,效果也可能天差地别——有人能用 AI 快速生成精准方案,有人却只能得到笼统回答。这背后的关键差异,在于提示词工程的应用能力。 北京大…...
SSH密码更改
Windows User目录下的.ssh/config,全部删除 linux 在主用户文件夹,ctrlh显示隐藏文件。删除.shh文件夹内所有文件。...
蓝桥备赛(四)- 数组(下)
一 、 字符数组 1.1 介绍 数组的元素如果是字符类型 , 这种数组就是字符数组 , 字符数组可以是一维数组 , 可以是二维数组 (多维数组)。 接下来主要讨论一维的字符数组 : char arr1[5] //一维数组 char arr2[3][5] // 二维数组 C语言 中…...
基金 word-->pdf图片模糊的解决方法
1. 首先需要Adobe或福昕等pdf阅读器。 2. word中 [文件]--[打印],其中打印机选择pdf阅读器,例如此处我选择福昕阅读器。 3. 选择 [打印机属性]--[编辑]--[图像],将所有的采样、压缩均设置为 关闭。点击[另存为],保存为 基金报告…...
身为小兵,如何提升不可替代性?
之前聊过,研发、PIE、PE、可靠性等岗位,主要是对物的工作, 这类岗位,如何提升不可替代性? 我的经验是,学会识别创造性工作or重复性工作。 尽可能地做创造性工作,推重复性工作。 销售、采购、HR等岗位,主要是对人的工作, 这类岗位,如何提升不可替代性? 我的思考…...
easyExcel使用案例有代码
easyExcel 入门,完成web的excel文件创建和导出 easyExcel官网 EasyExcel 的主要特点如下: 1、高性能:EasyExcel 采用了异步导入导出的方式,并且底层使用 NIO 技术实现,使得其在导入导出大数据量时的性能非常高效。 2、易于使…...
linux服务器更新jar包脚本
【需求】Java每次发布新的版本都需要先kill掉原来的服务,然后再启动新的包 有了这个脚本只需要把包替换掉,服务会自动kill 以8184 为例 完整的脚本如下 #!/bin/bash# 检查端口 8184 是否被占用 PORT8184 PID$(lsof -t -i:$PORT)if [ -n "$PID…...
Tomcat 乱码问题彻底解决
1. 终端乱码问题 找到 tomcat 安装目录下的 conf —> logging.properties .修改ConsoleHandler.endcoding GBK (如果在idea中设置了UTF-8字符集,这里就不需要修改) 2. CMD命令窗口设置编码 参考:WIN10的cmd查看编码方式&…...
dify绑定飞书多维表格
dify 绑定飞书和绑定 notion 有差不多的过程,都需要套一层应用的壳子,而没有直接可以访问飞书文档的 API。本文记录如何在dify工具中使用新增多条记录工具。 创建飞书应用 在飞书开放平台创建一个应用,个人用户创建企业自建应用。 自定义应…...
深入浅出:插入排序算法完全解析
1. 什么是插入排序? 插入排序(Insertion Sort)是一种简单的排序算法,其基本思想与我们整理扑克牌的方式非常相似。我们将扑克牌从第二张开始依次与前面已排序的牌进行比较,将其插入到合适的位置,直到所有牌…...
MySQL--DQL、DML、DDL、DCL概念与区别
在SQL中,根据功能和操作对象的不同,通常将语文分为四大类:DQL(数据查询语言)、DML(数据操作语言)、DDL(数据定义语言)、DCL(数据控制语言) 一、D…...
【设计原则】里氏替换原则(LSP):构建稳健继承体系的黄金法则
深入理解里氏替换原则(LSP)及其在C#中的实践 一、什么是里氏替换原则?二、为什么需要LSP?三、经典违反案例:矩形与正方形问题四、正确的设计实践方案1:通过接口分离方案2:使用抽象类 五、LSP的关…...
SQL的select语句完整的执行顺序
SQL的SELECT语句的执行顺序可以用"做菜流程"来类比理解。虽然我们写SQL时按SELECT…FROM…WHERE…顺序写,但数据库执行顺序完全不同。以下是通俗易懂的讲解(附流程图和示例): 🔧 执行顺序流程图:…...
【Vue3】浅谈setup语法糖
Vue3 的 setup 语法糖是通过 <script setup> 标签启用的特性,它是对 Composition API 的进一步封装,旨在简化组件的声明式写法,同时保留 Composition API 的逻辑组织能力。以下是其核心概念和原理分析: 一、<script setu…...
算法-二叉树篇27-把二叉搜索树转换为累加树
把二叉搜索树转换为累加树 力扣题目链接 题目描述 给出二叉 搜索 树的根节点,该树的节点值各不相同,请你将其转换为累加树(Greater Sum Tree),使每个节点 node 的新值等于原树中大于或等于 node.val 的值之和。 提…...
FPGA开发,使用Deepseek V3还是R1(3):系统级与RTL级
以下都是Deepseek生成的答案 FPGA开发,使用Deepseek V3还是R1(1):应用场景 FPGA开发,使用Deepseek V3还是R1(2):V3和R1的区别 FPGA开发,使用Deepseek V3还是R1&#x…...
《国密算法开发实战:从合规落地到性能优化》
前言 随着信息技术的飞速发展,信息安全已成为全球关注的焦点。在数字化时代,数据的保密性、完整性和可用性直接关系到国家、企业和个人的利益。为了保障信息安全,密码技术作为核心支撑,发挥着至关重要的作用。国密算法,即国家密码算法,是我国自主设计和推广的一系列密码…...
DeepSeek开源周Day5压轴登场:3FS与Smallpond,能否终结AI数据瓶颈之争?
2025年2月28日,DeepSeek开源周迎来了第五天,也是本次活动的收官之日。自2月24日启动以来,DeepSeek团队以每天一个开源项目的节奏,陆续向全球开发者展示了他们在人工智能基础设施领域的最新成果。今天,他们发布了Fire-F…...
Linux:进程替换
目录 进程程序替换 替换原理 进程替换相关函数 环境变量与进程替换函数 命令行解释器(my_xshell) 进程程序替换 上一篇进程控制讲到,父进程创建子进程就是为了让子进程去做一些另外的事情,但是不管怎么说,子进程的部分代码也还是父进程…...
CSS 日常开发常用属性总结
文章目录 CSS 日常开发常用属性总结一、 常用 CSS 属性1、布局相关(1)display:(2)position:(3)float:(4)clear: 2、尺寸与溢出&#x…...
Python 绘制迷宫游戏,自带最优解路线
1、需要安装pygame 2、上下左右移动,空格实现物体所在位置到终点的路线,会有虚线绘制。 import pygame import random import math# 迷宫单元格类 class Cell:def __init__(self, x, y):self.x xself.y yself.walls {top: True, right: True, botto…...
了解Java集合的概念和体系:Collection<T>、Collections与Stream的使用
学习目标 本文知识是对集合层级的介绍,应用开发中实际使用的是他们的子级,感兴趣的小伙伴或者想深入了解有关Java集合知识的朋友可以选择阅读! Stream的方法使用使用部分代码块内大多有两种实现方式,是为了更好的理解方法底层的代…...
扫描局域网可用端口
site: https://mengplus.top #SiliconFlow : 在Linux系统,你可以使用一个简单的Bash脚本来扫描局域网中可用的端口。这个脚本可以使用nmap工具来实现。nmap是一个强大的网络扫描工具,可以用来探测网络中的主机和端口。 以下是一个简单的Bash脚本&#…...
算法分析 —— 《栈》
文章目录 删除字符串中的所有相邻重复项题目描述:代码实现:代码解析: 比较含退格的字符串题目描述:代码实现:代码解析: [基本计算器 II](https://leetcode.cn/problems/remove-all-adjacent-duplicates-in-…...
693. 交替位二进制数
交替位二进制数 题目描述尝试做法推荐做法 题目描述 给定一个正整数,检查它的二进制表示是否总是 0、1 交替出现:换句话说,就是二进制表示中相邻两位的数字永不相同。 示例 1: 输入:n 5 输出:true 解释…...
uniapp中使用leaferui使用Canvas绘制复杂异形表格的实现方法
需求: 如下图,要实现左图的样式,先实现框架,文字到时候 往里填就行了,原来的解决方案是想用css,html来实现,发现实现起来蛮麻烦的。我也没找到合适的实现方法,最后换使用canvas来实现ÿ…...
Java 反射(Reflection)的原理和应用
反射(Reflection)是 Java 语言的一项强大功能,它允许程序在运行时动态地获取类的信息,并且可以操作这些信息,如创建对象、调用方法、访问字段等。反射机制的核心在于 Java 的 类加载机制 和 动态类型检查,使…...
Linux top 常用参数记录
top命令经常用来监控linux的系统状况,能实时显示系统中各个进程、线程的资源占用情况,是常用的性能分析工具。 一些常用参数记录 top的使用方式 top [-d number] | top [-bnp] # 5s 更新一次 top -d 5# 进行2次top命令的输出结果 top -n 2# 查看进程的…...
hive之LEAD 函数详解
1. 函数概述 LEAD 是 Hive 中的窗口函数,用于获取当前行之后指定偏移量处的行的值。常用于分析时间序列数据、计算相邻记录的差异或预测趋势。 2. 语法 LEAD(column, offset, default) OVER ([PARTITION BY partition_column] [ORDER BY order_column [ASC|DESC]…...
Element Plus中el-tree点击的节点字体变色加粗
el-tree标签设置 <el-tree class"tree":data"treeData":default-expand-all"true":highlight-current"true"node-click"onTreeNodeClick"><!-- 自定义节点内容,点击的节点字体变色加粗 --><!-- 动…...
.gitignore 设置后不见效的解决方法中,方案一就可以了
遇到的问题:你的 .gitignore 文件中包含了 unpackage/ 目录,但它不起作用的原因可能有以下几个: 1. 文件或目录已经被 Git 跟踪 .gitignore 只能忽略 未被 Git 追踪 的文件或目录。如果 unpackage/ 目录已经被提交到 Git 版本库中ÿ…...
git提交管理
git提交管理 scoop install nodejs # windows npm install --save-dev commitlint/config-conventional commitlint/cli # non-windows npm install --save-dev commitlint/{cli,config-conventional} # windows将commitlint.config.js修改为utf8编码, 默认utf16编码 echo &qu…...
DeepSeek八大组合软件,效率加倍
DeepSeek王炸组合:开启2025年高效工作与创意新时代 在科技飞速发展的2025年,人工智能和各类工具的融合正不断重塑我们的工作与生活方式。DeepSeek作为一款强大的工具,与众多应用组成的王炸组合,展现出了令人瞩目的能力。今天&…...
TCP和UDP比较
以下是 TCP(传输控制协议) 和 UDP(用户数据报协议) 的详细对比,涵盖核心特性、应用场景及技术差异: 1. 核心特性对比 特性TCPUDP连接方式面向连接(需三次握手建立连接)无连接&#…...
【实战篇】【深度解析DeepSeek:从机器学习到深度学习的全场景落地指南】
一、机器学习模型:DeepSeek的降维打击 1.1 监督学习与无监督学习的"左右互搏" 监督学习就像学霸刷题——给标注数据(参考答案)训练模型。DeepSeek在信贷风控场景中,用逻辑回归模型分析百万级用户数据,通过特征工程挖掘出"凌晨3点频繁申请贷款"这类魔…...
Postgresql高可用之Pacemaker+Corosync
简介 Pacemaker 是 ClusterLabs 开源高可用性集群堆栈的资源管理器。它协调配置、启动、监控和跨所有集群节点恢复相互关联的服务。在这套高可用架构用会用到Pacemaker、Corosync以下是对其功能作用的说明。 Corosync :主要负责 集群通信和成员管理,它用…...
智能成绩表
智能成绩表 真题目录: 点击去查看 E 卷 100分题型 题目描述 小明来到学校当老师,需要将学生按考试总分或单科分数进行排名,你能帮帮他吗? 输入描述 第 1 行输入两个整数,学生人数 n 和科目数量 m。 0 < n < 1000 < m < 10第 2 行输入 m 个科目名称,彼此之…...