当前位置: 首页 > news >正文

MCP协议的Streamable HTTP:革新数据传输的未来

引言

在数字化时代,数据传输的效率和稳定性是推动技术进步的关键。MCP(Model Context Protocol)作为AI生态系统中的重要一环,通过引入Streamable HTTP传输机制,为数据交互带来了革命性的变化。本文将深入解读MCP协议的Streamable HTTP,从会话协商到正式通信传输数据的全过程,探讨其技术架构、协议内容、实现方式以及对AI应用的影响。

技术架构

MCP协议采用客户端-服务器架构,其核心组件包括:

  1. MCP主机(MCP Host):包含MCP客户端的应用程序,如Claude Desktop、Cursor IDE等AI工具。
  2. MCP客户端(MCP Client):在主机内部与服务器保持1:1连接的协议实现。
  3. MCP服务器(MCP Server):轻量级程序,通过标准化协议暴露特定功能,可以是本地Node.js/Python程序或远程服务。

MCP服务器提供三类标准能力:

  • 资源(Resources):如文件读取、API数据获取。
  • 工具(Tools):第三方服务或功能函数,如Git操作、浏览器控制。
  • 提示词(Prompts):预定义的任务模板,增强模型特定场景表现。

Streamable HTTP的协议内容

Streamable HTTP作为MCP协议的一项重大更新,旨在解决传统HTTP+SSE方案的局限性,同时保留其优势。其核心内容包括以下几个方面:

  1. 统一消息入口:所有客户端到服务器的消息都通过/message端点发送,不再需要专门的SSE端点。
  2. 动态升级SSE流:服务器可以根据需要将客户端发往/message的请求升级为SSE连接,用于推送通知或请求。
  3. 会话管理机制:客户端通过请求头中的Mcp-Session-Id与服务器建立会话,服务器可选择是否维护会话状态。
  4. 支持无状态服务器:服务器可以选择完全无状态运行,不再需要维持长期连接。

实现方式

从会话协商到正式通信传输数据

1. 会话协商

会话协商是Streamable HTTP通信的初始阶段,客户端与服务器通过以下步骤建立会话:

  1. 客户端发送初始化请求:客户端通过HTTP POST向MCP服务器的/message端点发送一个InitializeRequest消息,携带协议版本和客户端能力信息。
  2. 服务器响应初始化:服务器收到请求后,返回一个InitializeResult消息,包含服务器支持的协议版本、服务器能力以及会话ID(Mcp-Session-Id)。
  3. 客户端发送已初始化通知:客户端收到服务器的响应后,发送一个Initialized通知,告知服务器初始化已完成。

示例:客户端发送初始化请求

POST /message HTTP/1.1
Host: mcp.example.com
Content-Type: application/json
Accept: text/event-stream, application/json{"jsonrpc": "2.0", "method": "initialize", "params": {"clientInfo": {"name": "MCP Client", "version": "1.0"}, "capabilities": {}}}

示例:服务器响应初始化

HTTP/1.1 200 OK
Content-Type: application/json
Mcp-Session-Id: 12345{"jsonrpc": "2.0", "id": 1, "result": {"serverInfo": {"name": "MCP Server", "version": "1.0"}, "capabilities": {}}}

示例:客户端发送已初始化通知

POST /message HTTP/1.1
Host: mcp.example.com
Content-Type: application/json
Accept: text/event-stream, application/json
Mcp-Session-Id: 12345{"jsonrpc": "2.0", "method": "initialized", "params": {}}
2. 正式通信传输数据

会话建立后,客户端和服务器可以通过以下步骤进行正式通信:

  1. 客户端发送消息:客户端通过HTTP POST向MCP服务器的/message端点发送JSON-RPC消息,携带会话标识Mcp-Session-Id
  2. 服务器处理请求并响应:服务器根据请求内容处理消息,并通过SSE流或JSON对象返回响应。
  3. 动态升级为SSE流:如果需要实时推送消息,服务器可以将连接升级为SSE流。
  4. 断线重连与数据恢复:如果网络波动导致连接中断,客户端可以携带Last-Event-ID重新连接,服务器根据该ID重放未发送的消息。

示例:客户端发送消息

POST /message HTTP/1.1
Host: mcp.example.com
Content-Type: application/json
Accept: text/event-stream, application/json
Mcp-Session-Id: 12345{"jsonrpc": "2.0", "id": 1, "method": "get_file", "params": {"path": "/example.txt"}}

示例:服务器响应并升级为SSE流

HTTP/1.1 200 OK
Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive
Mcp-Session-Id: 12345data: {"jsonrpc": "2.0", "id": 1, "result": "File content here"}

示例:客户端断线重连

GET /message HTTP/1.1
Host: mcp.example.com
Accept: text/event-stream
Last-Event-ID: 12345
Mcp-Session-Id: 12345

示例:服务器重放未发送的消息

data: {"jsonrpc": "2.0", "id": 2, "result": "Continued content here"}

服务端代码实现

from datetime import datetime
from starlette.applications import Starlette
from starlette.requests import Request
from starlette.routing import Route
from starlette.responses import JSONResponse, StreamingResponse
import json
import uuid
from starlette.middleware.cors import CORSMiddleware
import asyncio
from typing import Dict, Any
import aiofiles
import random# 存储会话ID和对应的任务队列
sessions: Dict[str, Dict[str, Any]] = {}# 添加CORS支持
app = Starlette()
app.add_middleware(CORSMiddleware,allow_origins=["*"],allow_credentials=True,allow_methods=["*"],allow_headers=["*"],expose_headers=["Mcp-Session-Id"],
)@app.route('/message', methods=["POST", "GET"])
async def handle_message(request: Request):"""处理POST和GET请求。"""session_id = request.headers.get("Mcp-Session-Id") or request.query_params.get("Mcp-Session-Id")if request.method == "POST":try:data = await request.json()if data.get("method") == "initialize":# 初始化会话session_id = str(uuid.uuid4())sessions[session_id] = {"initialized": True,"task_queue": asyncio.Queue()}response = JSONResponse(content={"jsonrpc": "2.0","id": data.get("id"),"result": {"serverInfo": {"name": "MCP Server", "version": "1.0"},"capabilities": {},},})response.headers["Mcp-Session-Id"] = session_idreturn responseelif session_id and sessions.get(session_id, {}).get("initialized"):# 处理已初始化的请求if data.get("method") == "get_file":try:# 异步读取文件内容content = await async_read_file(data.get("params", {}).get("path", ""))return JSONResponse(content={"jsonrpc": "2.0","id": data.get("id"),"result": content,})except Exception as e:return JSONResponse(content={"jsonrpc": "2.0","id": data.get("id"),"error": f"Error reading file: {str(e)}",})else:return JSONResponse(content={"error": "Unknown method"})else:return JSONResponse(content={"error": "Session not initialized"}, status_code=400)except Exception as e:return JSONResponse(content={"error": f"Internal server error: {str(e)}"}, status_code=500)elif request.method == "GET":# 处理SSE流请求if not session_id or session_id not in sessions:return JSONResponse(content={"error": "Session not found"}, status_code=404)async def event_generator(session_id):while True:try:message = await asyncio.wait_for(sessions[session_id]["task_queue"].get(), timeout=10)  # 超时时间10秒yield f"data: {json.dumps(message)}\n\n"except asyncio.TimeoutError as e:yield f"data: {e}\n\n"  # 发送空数据作为心跳包,防止超时断开return StreamingResponse(event_generator(session_id), media_type="text/event-stream")async def async_read_file(path: str) -> str:"""异步读取文件内容。"""try:async with aiofiles.open(path, "r") as file:content = await file.read()return contentexcept Exception as e:raise Exception(f"Error reading file: {str(e)}")async def background_task(session_id: str, task: Dict[str, Any]):"""后台任务处理。"""# 模拟耗时操作await asyncio.sleep(1)# 将结果放入任务队列sessions[session_id]["task_queue"].put_nowait(task)@app.on_event("startup")
async def startup_event():async def push_test_messages():while True:sp = random.randint(1, 3)await asyncio.sleep(sp)  # 每5秒推送一个消息for session_id in sessions.keys():if sessions[session_id]["initialized"]:sessions[session_id]["task_queue"].put_nowait({"message": f"Hello from server!", "sleep": sp,"datetime": datetime.now().strftime("%Y-%m-%d %H:%M:%S")})asyncio.create_task(push_test_messages())  # 创建后台任务if __name__ == "__main__":import uvicornuvicorn.run(app, host="0.0.0.0", port=8000)

客户端代码实现

import httpx
import json
import asyncio
import aiofilesclass MCPClient:def __init__(self, server_url: str):self.server_url = server_urlself.session_id = Noneself.headers = {"Content-Type": "application/json","Accept": "text/event-stream, application/json"}async def initialize(self):"""初始化会话。"""async with httpx.AsyncClient() as client:try:response = await client.post(f"{self.server_url}/message",headers=self.headers,json={"jsonrpc": "2.0","method": "initialize","params": {"clientInfo": {"name": "MCP Client", "version": "1.0"},"capabilities": {},},},)response.raise_for_status()self.session_id = response.headers.get("Mcp-Session-Id")print(f"Session ID: {self.session_id}")return self.session_idexcept Exception as e:print(f"Failed to initialize session: {e}")return Noneasync def send_message(self, method: str, params: dict = None):"""发送消息。"""if not self.session_id:await self.initialize()async with httpx.AsyncClient() as client:try:response = await client.post(f"{self.server_url}/message",headers={"Mcp-Session-Id": self.session_id, **self.headers},json={"jsonrpc": "2.0","id": 1,"method": method,"params": params or {},},)response.raise_for_status()return response.json()except Exception as e:print(f"Failed to send message: {e}")return Noneasync def listen_sse(self):if not self.session_id:await self.initialize()async with httpx.AsyncClient(timeout=None) as client:  # 取消超时限制try:async with client.stream("GET",f"{self.server_url}/message",headers={"Mcp-Session-Id": self.session_id, **self.headers},) as response:async for line in response.aiter_lines():if line.strip():  # 避免空行print(f"SSE Message: {line}")except Exception as e:print(f"Failed to listen SSE: {e}")await self.reconnect()async def reconnect(self):"""断线重连。"""print("Attempting to reconnect...")await asyncio.sleep(5)  # 等待5秒后重试await self.initialize()await self.listen_sse()async def main():client = MCPClient("http://localhost:8000")await client.initialize()response = await client.send_message("get_file", {"path": "/Users/houjie/PycharmProjects/python-sdk/examples/mcp-server/example.txt"})print(f"Response: {response}")await client.listen_sse()if __name__ == "__main__":asyncio.run(main())

前端页面代码实现

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>MCP Streamable HTTP Demo</title><style>body {font-family: Arial, sans-serif;margin: 0;padding: 20px;background-color: #f5f5f5;}.container {max-width: 800px;margin: 0 auto;background-color: white;padding: 20px;border-radius: 8px;box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);}h1 {text-align: center;color: #333;}.message-area {margin-top: 20px;}.message {padding: 10px;margin-bottom: 10px;border-radius: 4px;background-color: #e9f7fe;border-left: 4px solid #0099cc;}.sse-message {padding: 10px;margin-bottom: 10px;border-radius: 4px;background-color: #f0f9ff;border-left: 4px solid #0077cc;}button {background-color: #0099cc;color: white;border: none;padding: 10px 15px;border-radius: 4px;cursor: pointer;font-size: 14px;}button:hover {background-color: #0077cc;}input[type="text"] {width: 100%;padding: 10px;margin-bottom: 10px;border: 1px solid #ddd;border-radius: 4px;font-size: 14px;}</style>
</head>
<body><div class="container"><h1>MCP Streamable HTTP Demo</h1><div><input type="text" id="serverUrl" placeholder="Enter server URL" value="http://localhost:8000"><button id="initBtn">Initialize Session</button></div><div id="sessionId"></div><div><input type="text" id="filePath" placeholder="Enter file path"><button id="sendBtn">Send Message</button></div><div class="message-area" id="messages"></div></div><script>let client = null;let sessionInitialized = false;document.getElementById('initBtn').addEventListener('click', async () => {const serverUrl = document.getElementById('serverUrl').value;client = new MCPClient(serverUrl);await client.initialize();sessionInitialized = true;document.getElementById('sessionId').textContent = `Session ID: ${client.session_id}`;});document.getElementById('sendBtn').addEventListener('click', async () => {if (!sessionInitialized) {alert('Please initialize the session first.');return;}const filePath = document.getElementById('filePath').value;const response = await client.send_message('get_file', { path: filePath });addMessage(`Response: ${JSON.stringify(response)}`);});class MCPClient {constructor(serverUrl) {this.serverUrl = serverUrl;this.session_id = null;this.headers = {'Content-Type': 'application/json','Accept': 'text/event-stream, application/json'};}async initialize() {try {const response = await fetch(`${this.serverUrl}/message`, {method: 'POST',headers: this.headers,body: JSON.stringify({jsonrpc: '2.0',method: 'initialize',params: {clientInfo: { name: 'MCP Client', version: '1.0' },capabilities: {}}})});if (!response.ok) {throw new Error(`HTTP error! status: ${response.status}`);}this.session_id = response.headers.get('Mcp-Session-Id');addMessage(`Session ID: ${this.session_id}`);this.listen_sse();} catch (error) {addMessage(`Failed to initialize session: ${error}`);}}async send_message(method, params) {if (!this.session_id) {await this.initialize();}try {const response = await fetch(`${this.serverUrl}/message`, {method: 'POST',headers: { 'Mcp-Session-Id': this.session_id, ...this.headers },body: JSON.stringify({jsonrpc: '2.0',id: 1,method: method,params: params || {}})});if (!response.ok) {throw new Error(`HTTP error! status: ${response.status}`);}return await response.json();} catch (error) {addMessage(`Failed to send message: ${error}`);return null;}}listen_sse() {if (!this.session_id) {return;}const eventSource = new EventSource(`${this.serverUrl}/message?Mcp-Session-Id=${this.session_id}`, {headers: { 'Mcp-Session-Id': this.session_id }});eventSource.onmessage = (event) => {addSSEMessage(event.data);};eventSource.onerror = (error) => {addMessage(`Failed to listen SSE: ${error}`);this.reconnect();};}async reconnect() {addMessage('Attempting to reconnect...');await new Promise(resolve => setTimeout(resolve, 5000));await this.initialize();this.listen_sse();}}function addMessage(message) {const messagesDiv = document.getElementById('messages');const messageDiv = document.createElement('div');messageDiv.className = 'message';messageDiv.textContent = message;messagesDiv.appendChild(messageDiv);messagesDiv.scrollTop = messagesDiv.scrollHeight;}function addSSEMessage(message) {const messagesDiv = document.getElementById('messages');const messageDiv = document.createElement('div');messageDiv.className = 'sse-message';messageDiv.textContent = `SSE Message: ${message}`;messagesDiv.appendChild(messageDiv);messagesDiv.scrollTop = messagesDiv.scrollHeight;}</script>
</body>
</html>

运行步骤

  1. 安装依赖
    确保安装了所需的库:

    pip install starlette uvicorn httpx aiofiles
    
  2. 启动服务器
    将服务端代码保存为 server.py,然后运行以下命令启动服务器:

    uvicorn server:app --reload
    
  3. 运行客户端
    将客户端代码保存为 client.py,然后运行以下命令启动客户端:

    python client.py
    
  4. 打开前端页面
    将前端页面代码保存为 index.html,然后在浏览器中打开该文件。

示例运行效果

客户端输出
Session ID: 587bb6ad-08f5-4102-8b27-4c276e9d7815
Response: {'jsonrpc': '2.0', 'id': 1, 'result': 'File content here'}
Listening for SSE messages...
SSE Message: data: {"message": "Hello from server!", "sleep": 1, "datetime": "2024-01-01 12:00:00"}
SSE Message: data: {"message": "Hello from server!", "sleep": 2, "datetime": "2024-01-01 12:00:02"}
...
服务器输出
INFO:     Started server process [12345]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
INFO:     127.0.0.1:51487 - "POST /message HTTP/1.1" 200 OK
前端页面效果

前端页面将显示会话ID、发送的消息以及接收到的SSE流消息。

调试

  1. 检查服务器日志:查看服务器日志,确认是否生成了 Mcp-Session-Id 并返回给客户端。
  2. 检查网络请求:使用浏览器开发者工具(F12),查看网络请求的响应头,确认是否包含 Mcp-Session-Id
  3. 检查跨域问题:确保服务器正确配置了 CORS,允许前端页面的域名和端口。

希望这些信息能够帮助你成功实现基于MCP协议的Streamable HTTP服务端、客户端和前端页面。

相关文章:

MCP协议的Streamable HTTP:革新数据传输的未来

引言 在数字化时代&#xff0c;数据传输的效率和稳定性是推动技术进步的关键。MCP&#xff08;Model Context Protocol&#xff09;作为AI生态系统中的重要一环&#xff0c;通过引入Streamable HTTP传输机制&#xff0c;为数据交互带来了革命性的变化。本文将深入解读MCP协议的…...

基于 RK3588 的 YOLO 多线程推理多级硬件加速引擎框架设计(代码框架和实现细节)

一、前言 接续上一篇文章&#xff0c;这个部分主要分析代码框架的实现细节和设计理念。 基于RK3588的YOLO多线程推理多级硬件加速引擎框架设计&#xff08;项目总览和加速效果&#xff09;-CSDN博客https://blog.csdn.net/plmm__/article/details/146542002?spm1001.2014.300…...

stm32 can 遥控帧的问题

STM32单片机使用CAN协议进行通信 引用这个博客的一段话 CAN的遥控帧&#xff08;Remote Frame&#xff09;的主要作用是请求其他节点发送具 有特定ID的数据帧。具体来说&#xff0c;当一个节点需要从另一个节点获取数 据时&#xff0c;它可以发送一个遥控帧&#xff0c;而不是…...

机器人基础知识-1

1.六轴机器人中的六轴是什么&#xff1f; 第一轴&#xff08;J1&#xff09;&#xff1a;底座旋转 控制机器人整体绕垂直轴旋转&#xff08;左右摆动&#xff09;&#xff0c;决定工作范围的水平方向。 第二轴&#xff08;J2&#xff09;&#xff1a;下臂前后摆动 驱动机器人的…...

JAVA- 锁机制介绍 进程锁

进程锁 基于文件的锁基于Socket的锁数据库锁分布式锁基于Redis的分布式锁基于ZooKeeper的分布式锁 实际工作中都是集群部署&#xff0c;通过负载均衡多台服务器工作&#xff0c;所以存在多个进程并发执行情况&#xff0c;而在每台服务器中又存在多个线程并发的情况&#xff0c;…...

如何在WordPress中强制用户使用强密码?

在如今网络安全备受关注的环境下&#xff0c;弱密码问题不容忽视。很多用户习惯在多个网站使用相同且简单的密码&#xff0c;这样一来&#xff0c;若不强制他们在 WordPress 网站上使用强密码&#xff0c;网站的安全性就会受到威胁。尤其对于在线商店、会员网站、多作者博客等站…...

鸿蒙NEXT开发Base64工具类(ArkTs)

import util from ohos.util;/*** Base64 工具类* author: 鸿蒙布道师* since: 2025/03/31*/ export class Base64Util {/*** 创建 Base64Helper 实例* returns Base64Helper 实例*/private static createBase64Helper(): util.Base64Helper {return new util.Base64Helper();}…...

基于HUTOOL实现RSA工具类

一、前言&#xff1a;用 Hutool 简化 RSA 加密开发&#xff0c;提升代码安全与效率 在当今数据安全至关重要的时代&#xff0c;RSA 非对称加密作为保护敏感信息的核心技术&#xff0c;广泛应用于通信加密、数字签名、密钥交换等场景。然而&#xff0c;手动实现 RSA 算法涉及复…...

flink 分组窗口聚合 与 窗口表值函数聚合 的区别

警告&#xff1a;分组窗口聚合已经过时。推荐使用更加强大和有效的窗口表值函数聚合。 参考官方文档 在 Apache Flink 中&#xff0c;分组窗口聚合&#xff08;Group Window Aggregation&#xff09; 和 窗口表值函数聚合&#xff08;Windowing TVF Aggregation&#xff09;…...

prompt_status:5: command not found: wc解决办法

问题出现背景 想配置uniapp的命令行&#xff0c;在.zprofile配置路径的时候PATH 前面少打了一个$&#xff0c;执行了 source&#xff0c;导致各种命令都失效。 解决办法 用fider 打开用户文件夹&#xff0c;Command Shift .显示隐藏文件&#xff0c;用文本编辑器修改一下&…...

《STL 六大组件之容器篇:简单了解 list》

目录 一、list 简介二、list 的常用接口1. 构造函数&#xff08;constructor &#xff09;2. 迭代器&#xff08;iterator&#xff09;3. 容量、修改和访问&#xff08;capacity 、modify and access&#xff09; 一、list 简介 简单来说&#xff0c;list 就是数据结构初阶中学…...

向量数据库学习笔记(2) —— pgvector 用法 与 最佳实践

关于向量的基础概念&#xff0c;可以参考&#xff1a;向量数据库学习笔记&#xff08;1&#xff09; —— 基础概念-CSDN博客 一、 pgvector简介 pgvector 是一款开源的、基于pg的、向量相似性搜索 插件&#xff0c;将您的向量数据与其他数据统一存储在pg中。支持功能包括&…...

TCP的连接建立

面向连接 定义&#xff1a;在发送数据之前&#xff0c;需要建立一条点到点的连接 &#xff08;参数协商的过程。因为tcp要保证可靠&#xff0c;所以tcp通信是发生在双方之间、两端之间的&#xff0c;两端在正式发送数据之前需要约定一些初始参数&#xff0c;这个过程就是面向连…...

如何让AI帮你做用户运营:用户消费偏好分层和洞察

随着deepseek的爆火&#xff0c;我一直在想能不能用AI来帮我做用户运营&#xff0c;目前deepseek只能提供框架层面的运营建议&#xff0c;还无法实现将订单数据给到它&#xff0c;能够自动化分析并将用户分层&#xff0c;并给出可视化的运营洞察报表。但是&#xff0c;我要告诉…...

二分答案-P8647 [蓝桥杯 2017 省 AB] 分巧克力

题解&#xff1a;P8647 [蓝桥杯 2017 省 AB] 分巧克力 题目传送门 题目链接 一、题目描述 小明有N块不同尺寸的巧克力&#xff0c;需要切出K块相同大小的正方形巧克力分给小朋友们。要求找到能满足条件的最大的正方形边长。 二、题目分析 我们需要从N块巧克力中切出K个相…...

搜广推校招面经六十一

美团推荐算法 一、ANN算法了解么&#xff1f;说几种你了解的ANN算法 ANN 近似最近邻搜索&#xff08;Approximate Nearest Neighbor Search&#xff09;算法 1.1. KD-Tree&#xff08;K-Dimensional Tree&#xff0c;K 维树&#xff09; 类型: 空间划分数据结构适用场景: 低…...

某地老旧房屋自动化监测项目

1. 项目简介 自从上个世纪90年代以来&#xff0c;我国经济发展迅猛&#xff0c;在此期间大量建筑平地而起&#xff0c;并且多为砖混结构的住房&#xff0c;使用寿命通常约为30-50年&#xff0c;钢筋混凝土结构&#xff0c;钢结构等高层建筑&#xff0c;这些建筑在一般情况下的…...

【第一节】Python爬虫基础-HTTP基本原理

目录 前言 一、URI和URL是什么 二、什么是超文本 三、HTTP和HTTPS的区别 四、HTTP请求过程 五、请求 六、响应 前言 在着手开发爬虫程序之前&#xff0c;我们需要先掌握一些基础概念。本节将详细讲解HTTP的基本工作原理&#xff0c;重点分析从浏览器输入网址到获取网页内…...

docker打包使用有头模式playwright

1.打包镜像 创建Dockerfile文件如下 # playywright 官方镜像 FROM mcr.microsoft.com/playwright:v1.37.0-jammy# 设置非交互式环境变量和时区 ENV DEBIAN_FRONTENDnoninteractive ENV TZEtc/UTC# 安装 Python 3.9 和 pip&#xff08;修复时区阻塞问题&#xff09; RUN apt-g…...

VuePress 和 Docusaurus的对比

VuePress 和 Docusaurus 是两个流行的现代静态网站生成器 vuepress:首页 | VuePress Docusaurus&#xff1a;Docusaurus 博客 | Docusaurus中文文档 | Docusaurus中文网 一、技术栈和设计理念 VuePress 技术栈&#xff1a;基于Vue.js&#xff0c;专为技术文档设计&#xff0c…...

JAVA数据库增删改查

格式 Main.java(测试类) package com.example;import com.example.dao.UserDao; import com.example.model.User;public class Main {public static void main(String[] args) {UserDao userDao new UserDao();// 测试添加用户System.out.println(" 添加用户 ");Us…...

MSTP多域生成树

协议信息 MSTP 兼容 STP 和 RSTP&#xff0c;既可以快速收敛&#xff0c;又提供了数据转发的多个冗余路径&#xff0c;在数据转发过程中实现 VLAN 数据的负载均衡。 MSTP 可以将一个或多个 VLAN 映射到一个 Instance&#xff08;实例&#xff09;&#xff08;一个或多个 VLAN…...

HashMap 在 JDK 1.7 和 JDK 1.8 有什么区别

HashMap 在 JDK 1.7 和 JDK 1.8 中的实现存在显著差异&#xff0c;主要体现在以下几个方面&#xff1a; 1. 数据结构的变化 • JDK 1.7&#xff1a;HashMap 的底层数据结构是数组 单向链表。当哈希冲突发生时&#xff0c;新的元素会插入到链表的头部&#xff08;头插法&#…...

Mysql忽略大小写

🚀欢迎来到我的【Mysql】专栏🚀 🙋我是小蜗,一名在职牛马。🐒我的博客主页​​​​​​ ➡️ ➡️ 小蜗向前冲的主页🙏🙏欢迎大家的关注,你们的关注是我创作的最大动力🙏🙏在 MySQL 中取消大小写区分主要涉及以下两个层面的配置,具体操作如下: 一、表名大…...

基于TradingView和CTPBee的自动化期货交易系统实现

引言 在量化交易领域&#xff0c;TradingView因其强大的技术分析工具和丰富的指标库而广受欢迎&#xff0c;但是其不支持国内期货自动化交易&#xff0c;CTPBee则是一个优秀的国产Python期货交易接口。本文将介绍如何将两者结合&#xff0c;实现一个完整的自动化交易系统。 本…...

昇腾CANN算子共建仓CANN-Ops正式上线Gitee,首批算子已合入

在人工智能技术呈指数级发展的今天&#xff0c;AI创新已走向更底层的算法创新&#xff0c;以DeepSeek为例&#xff0c;通过MoE模型架构和底层算法创新&#xff0c;不仅获取极佳的模型性能&#xff0c;又更大程度释放硬件性能&#xff0c;降低硬件使用成本。 算子&#xff0c;作…...

基于PyQt5的自动化任务管理软件:高效、智能的任务调度与执行管理

基于PyQt5的自动化任务管理软件&#xff1a;高效、智能的任务调度与执行管理 相关资源文件已经打包成EXE文件&#xff0c;可双击直接运行程序&#xff0c;且文章末尾已附上相关源码&#xff0c;以供大家学习交流&#xff0c;博主主页还有更多Python相关程序案例&#xff0c;秉着…...

Pycharm(八):字符串切片

一、字符串分片介绍 对操作的对象截取其中一部分的操作&#xff0c;比如想要获取字符串“888666qq.com前面的qq号的时候就可以用切片。 字符串、列表、元组都支持切片操作。 语法&#xff1a;字符串变量名 [起始:结束:步长] 口诀&#xff1a;切片其实很简单&#xff0c;只顾头来…...

C++编程学习笔记:函数相关特性、引用与编译流程

目录 一、函数的缺省参数 &#xff08;一&#xff09;全缺省参数 &#xff08;二&#xff09;半缺省参数 二、函数重载 &#xff08;一&#xff09;参数类型不同 &#xff08;二&#xff09;参数个数不同 &#xff08;三&#xff09;参数类型顺序不同 三、引用相关问题…...

Nginx 配置 HTTPS 与 WSS 完整指南

Nginx 配置 HTTPS 与 WSS 完整指南 本教程将手把手教你如何为网站配置 HTTPS 加密访问&#xff0c;并通过反向代理实现安全的 WebSocket&#xff08;WSS&#xff09;通信。以 https://www.zhegepai.cn 域名为例&#xff0c;完整流程约需 30 分钟完成。 一、前置准备 1.1 域名…...

链表基本操作

文章目录 1、单链表1.1 链表的创建1.2 链表的遍历1.3 链表的删除1.4 链表的插入1.5 链表和数组 2、双向链表2.1 双链表的创建2.2 双链表的删除2.3 双链表的插入2.4 双向循环链表2.5 双链表优缺点 1、单链表 链表是一种物理存储单元上非连续、非顺序的存储结构&#xff0c;插入…...

【huggingface 数据下载】ssh / https 不同的下载流程,hf 镜像下载注意事项

ssh 下载流程 在 linux 服务器上生成 ssh key将 pub key 放入 huggingface 的 setting 中通过 git lfs install 然后 git clone githf.co … 来下载数据 遇到的问题 一直卡在 Updating files 后 卡住的可能原因&#xff1a; 系统当前限制了允许监视的最大文件数&#xff1…...

简单版CentOS7配置haproxy

一、实验步骤 1、自行下载pes的tar包 然后解压到家目录下 tar -xzvf pes.tar.gz 2、创建一个目录 mkdir docker-compose-pes-lb2 3、在这个目录下写两个文件docker-compose.yml和haproxy.cfg docker-compose.yml version: 3 services: db: image: mysql:5.7.44 container…...

leetcode146.LRU缓存

思路源自 【面试高频】146. LRU 缓存 采用哈希表双向链表 put一个键值对时&#xff0c;采用头插法将缓存块置于等级较高的位置&#xff0c;如果put数量超出限制&#xff0c;那么就将尾部的缓存块删除&#xff0c;以此达到置换的一个效果 get一个键值对也是同样的思路&#xf…...

SpringIoC和DI

文章目录 OCP开闭原则DIP(依赖倒置原则)IOC(控制反转)依赖注入DI基于XML配置Beanset注入构造注入 使用注解存储beanController方法注解Bean扫描路径依赖注入三种注入方式优缺点分析 引入 当我们写了一个程序&#xff0c;遵循SpringMVC三层架构&#xff0c;表现层调用业务逻辑层…...

vue 路由

目录 一、路由的使用 二、声明式导航 2.1 声明式导航 2.2 声明式导航路由传参 2.2.1.字符串写法 2.2.2.对象写法 2.2.3 query 传参和 param 传参总结 2.3 命名路由 2.4 可选操作符 2.5 props 参数 三、编程式导航 3.1 replace 和 push 跳转…...

JAVA常见的 JVM 参数及其典型默认值

在 Java 线上应用中&#xff0c;JVM 参数的默认值取决于具体的 JVM 实现&#xff08;如 Oracle JDK、OpenJDK、Zulu 等&#xff09;、版本&#xff08;如 Java 8、11、17 等&#xff09;以及运行环境&#xff08;物理机、容器等&#xff09;。以下是常见的 JVM 参数及其典型默认…...

文件压缩与解压(zip4j)

maven依赖 <dependency><groupId>net.lingala.zip4j</groupId><artifactId>zip4j</artifactId><version>2.11.5</version></dependency>示例 //参数配置ZipParameters parameters new ZipParameters();parameters.setCompres…...

【操作系统】查内存泄漏方法

【操作系统】查内存泄漏方法 1. 通用检测方法1.1 代码审查1.2 运行时监测 2.Linux平台检测工具2.1 Valgrind工具套件2.2 AddressSanitizer (ASan)2.3 mtrace 3.Windows平台检测工具3.1 Visual Studio诊断工具3.2 CRT调试堆 4.嵌入式系统检测方法4.1 RT-Thread内存检测4.2 自定义…...

oracle常用sql

获取主键 1. 查询主键的两种常用方法 Oracle 的主键信息存储在以下两个视图中&#xff1a; USER_CONSTRAINTS&#xff1a;存储当前用户下所有表的约束信息&#xff08;如主键、外键等&#xff09;。 USER_CONS_COLUMNS&#xff1a;存储约束对应的列信息。 方法 1&#xff…...

【第十三届“泰迪杯”数据挖掘挑战赛】【2025泰迪杯】【思路篇】A题解题全流程(持续更新)

【第十三届“泰迪杯”数据挖掘挑战赛】【2025泰迪杯】A题解题全流程-思路&#xff08;持续更新&#xff09; 写在前面&#xff1a; 1、A题、C题将会持续更新&#xff0c;陆续更新发布文章 2、赛题交流咨询Q群&#xff1a;1037590285 3、全家桶依旧包含&#xff1a; 代码、…...

Qt 信号量使用方法

Qt 信号量使用方法 QSemaphore 类 常用函数介绍 函数名称函数功能QSemaphore()构造并初始化对象acquire()尝试获取n个资源&#xff0c;如果没有那么多资源&#xff0c;线程将阻塞直到有n个资源可用available()返回当前信号量可用的资源个数&#xff0c;这个数永远不可能为负…...

C++进阶——封装哈希表实现unordered_map/set

与红黑树封装map/set基本相似&#xff0c;只是unordered_map/set是单向迭代器&#xff0c;模板多传一个HashFunc。 目录 1、源码及框架分析 2、模拟实现unordered_map/set 2.1 复用的哈希表框架及Insert 2.2 iterator的实现 2.2.1 iteartor的核心源码 2.2.2 iterator的实…...

AI Agent 实战:搭建个人在线旅游助手

AI Agent 实战&#xff1a;搭建个人在线旅游助手 本次实验中&#xff0c;我们将继续探索 Agent 的提示词&#xff0c;学习更加规范的提示词撰写方法。 本实验中你将掌握的知识点 使用 Dify 构建 Agent 的方法结构化的提示词撰写技巧变量的使用方法 1. 准备 在新建 Agent 之…...

CSS中的overflow属性

在 CSS 中&#xff0c;overflow 属性用于控制当一个元素的内容溢出其指定的区域时&#xff0c;应该如何处理溢出的部分。通常用于盒模型&#xff08;如 div&#xff09;中&#xff0c;指定内容超出容器时的显示方式。 overflow 属性的常用值&#xff1a; 1. visible&#xff08…...

【Unity】处理文字显示不全的问题

1.选中字体文件&#xff0c;检查 MultiAtlasTeextures 是否勾选&#xff0c;未勾选的话&#xff0c;先勾选保存后查看是否显示正常 2.勾选后未正常显示&#xff0c;则在搜索框中输入未显示的文本&#xff0c;确认字体图集是否包含该文本&#xff0c;然后点击Update Atlas Textu…...

蓝桥备赛指南(11):递归简介

递归的介绍 概念&#xff1a;递归是指函数直接或间接调用自身的过程。 解释递归的两个关键要素&#xff1a; 基本情况&#xff08;递归终止条件&#xff09;&#xff1a;递归函数中的一个条件&#xff0c;当满足该条件时&#xff0c;递归终止&#xff0c;避免无限递归。可以…...

Python 图片水印处理工具

自定义水印文本自定义水印位置支持图片裁剪支持各种图片格式 from PIL import Image, ImageDraw, ImageFont import osclass ImageWatermarker:def __init__(self, font_pathNone, font_size40):"""初始化水印处理器font_path: 字体文件路径&#xff0c;默认使…...

从零开始:如何打造一套完整的UI设计系统?

1. 建立色彩系统 色彩系统是设计系统的基础之一&#xff0c;它不仅影响界面的整体美感&#xff0c;还对用户体验有着深远的影响。首先&#xff0c;设计师需要定义主色调、辅助色和强调色&#xff0c;并确保这些颜色在不同场景下的应用保持一致。使用工具如Adobe Color或Coolor…...

Jenkins + CICD流程一键自动部署Vue前端项目(保姆级)

git仓库地址&#xff1a;参考以下代码完成,或者采用自己的代码。 南泽/cicd-test 拉取项目代码到本地 使用云服务器或虚拟机采用docker部署jenkins 安装docker过程省略 采用docker部署jenkins&#xff0c;注意这里的命令&#xff0c;一定要映射docker路径&#xff0c;否则无…...