一个接口同时支持 HTTP 和 Streamable HTTP:MCP 双协议实现深度解析
2025-10-29
深度学习
00

目录

一个接口同时支持 HTTP 和 Streamable HTTP:MCP 双协议实现深度解析
前言
一、基础概念:从 JSON-RPC 说起
1.1 什么是 JSON-RPC?
1.2 MCP 是什么?
二、两种传输模式的本质区别
2.1 HTTP (JSON-RPC) 模式
2.2 Streamable HTTP (SSE) 模式
三、核心魔法:StreamableHTTPServerTransport 如何同时支持两种模式?
3.1 MCP SDK 的智能判断
3.2 你的代码中的体现
3.3 工作流程对比
四、为什么需要 Accept 头的兼容处理?
4.1 Accept 头的作用
4.2 MCP SDK 的严格检查
4.3 兼容性问题
4.4 解决方案
五、Node.js / Nitro 框架中的请求处理
5.1 Nitro 是什么?
5.2 文件路由工作原理
5.3 defineEventHandler 解析
5.4 为什么要访问 event.node.req/res?
六、SSE (Server-Sent Events) 深入理解
6.1 SSE 是什么?
6.2 SSE 的格式规范
6.3 为什么 POST 响应是 202?
6.4 JavaScript 中使用 SSE
七、实战:手动测试两种模式
7.1 测试 HTTP 模式(Cursor 使用的方式)
7.2 测试 Streamable HTTP 模式(Inspector 使用的方式)
7.3 调试技巧
八、架构优势与设计思考
8.1 为什么同一个 Transport 支持两种模式?
8.2 与传统 REST API 的对比
8.3 性能考虑
九、常见问题与进阶话题
9.1 如果 SSE 连接断开会发生什么?
9.2 是否可以同时建立多个 SSE 连接?
9.3 为什么不用 WebSocket?
9.4 在生产环境中的注意事项
十、总结
10.1 核心要点回顾
10.2 技术栈总结
10.3 学习路径建议
10.4 扩展思考
参考资源

一个接口同时支持 HTTP 和 Streamable HTTP:MCP 双协议实现深度解析

前言

当你第一次看到这段代码时,可能会感到困惑:

typescript
展开代码
// server/api/mcp.post.ts const transport = new StreamableHTTPServerTransport(...) await transport.handleRequest(req, res, await readBody(event))

同一个 StreamableHTTPServerTransport,为什么既能处理 Cursor 的同步 HTTP 请求,又能处理 Inspector 的流式 SSE 连接?

这篇文章将揭开这个"魔法"背后的技术原理,带你理解 MCP 协议、HTTP vs Streamable HTTP 的本质区别,以及如何用一套代码优雅地支持两种模式。


一、基础概念:从 JSON-RPC 说起

1.1 什么是 JSON-RPC?

JSON-RPC 是一种轻量级的远程过程调用(RPC)协议,它的核心格式非常简单:

请求示例

json
展开代码
{ "jsonrpc": "2.0", "id": 1, "method": "get_hotest_latest_news", "params": { "id": "zhihu", "count": 10 } }

响应示例

json
展开代码
{ "jsonrpc": "2.0", "id": 1, "result": { "content": [ {"type": "text", "text": "[新闻标题](链接)"} ] } }

关键点:

  • 通过 method 字段指定要调用的方法
  • 通过 id 字段关联请求和响应
  • 协议本身不关心传输层如何实现

1.2 MCP 是什么?

MCP (Model Context Protocol) 是 Anthropic 推出的协议,用于 AI 应用与外部工具/资源的通信。它基于 JSON-RPC 2.0,定义了一套标准化的方法:

  • initialize - 初始化连接
  • tools/list - 列出可用工具
  • tools/call - 调用工具
  • logging/setLevel - 设置日志级别(可选)

MCP 的设计理念:协议层与传输层分离,这意味着:

  • 协议本身只定义消息格式
  • 传输可以用 STDIO、HTTP、WebSocket、SSE 等任何方式

这就是为什么 MCP 可以同时支持多种传输方式!


二、两种传输模式的本质区别

2.1 HTTP (JSON-RPC) 模式

这是最传统的 请求-响应 模式:

展开代码
客户端 服务端 | | |-- POST /api/mcp -------->| (发送 JSON-RPC 请求) | | (处理请求) |<----- 200 OK ------------| (返回完整响应) | | 连接关闭 连接关闭

特点

  • 每次请求打开一个新的 HTTP 连接
  • 服务端处理完后立即返回结果
  • 连接结束,不保持状态
  • 简单、稳定、兼容性好

实际 HTTP 请求

bash
展开代码
curl -X POST http://107.173.199.53:9044/api/mcp \ -H "Content-Type: application/json" \ --data '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'

响应

json
展开代码
{ "jsonrpc": "2.0", "id": 1, "result": { "tools": [...] } }

2.2 Streamable HTTP (SSE) 模式

这是一种 双通道 模式:

展开代码
客户端 服务端 | | |-- GET /api/mcp --------->| 建立 SSE 通道(持续连接) |<==== 保持连接 ==========| (心跳、事件流) | | |-- POST /api/mcp -------->| 发送 JSON-RPC 请求 | | (不立即返回) |<==== SSE: event ========| 通过 SSE 推送响应 |<==== SSE: event ========| 可以推送多条消息 | |

特点

  • 一个 GET 连接保持打开,用于接收服务端推送
  • POST 请求只发送数据,不等待响应
  • 响应通过 SSE 通道异步返回
  • 支持流式输出、实时通知、双向通信

SSE 通道示例

bash
展开代码
curl -N http://107.173.199.53:9044/api/mcp # 连接保持打开,服务端可以持续推送: # data: {"jsonrpc":"2.0","id":1,"result":{...}} # # data: {"jsonrpc":"2.0","id":2,"result":{...}}

三、核心魔法:StreamableHTTPServerTransport 如何同时支持两种模式?

3.1 MCP SDK 的智能判断

让我们看看 @modelcontextprotocol/sdk 的源码逻辑(简化版):

typescript
展开代码
class StreamableHTTPServerTransport { async handleRequest(req, res, body?) { // 关键判断:根据 HTTP 方法选择模式 if (req.method === 'GET') { // GET 请求 → 建立 SSE 通道 return this.handleSSE(req, res) } else if (req.method === 'POST') { // POST 请求 → 处理 JSON-RPC return this.handleJSONRPC(req, res, body) } } private handleSSE(req, res) { // 设置 SSE 响应头 res.setHeader('Content-Type', 'text/event-stream') res.setHeader('Cache-Control', 'no-cache') res.setHeader('Connection', 'keep-alive') // 保持连接,将响应通道存储起来 this._sseConnection = res // 定期发送心跳防止超时 this._heartbeat = setInterval(() => { res.write(': ping\n\n') }, 30000) } private async handleJSONRPC(req, res, body) { const request = JSON.parse(body) // 检查是否有活跃的 SSE 连接 if (this._sseConnection) { // 有 SSE 通道 → Streamable HTTP 模式 // 处理请求但不立即返回,而是通过 SSE 推送 const result = await this.processRequest(request) this._sseConnection.write(`data: ${JSON.stringify(result)}\n\n`) res.status(202).end() // 202 Accepted } else { // 没有 SSE 通道 → 传统 HTTP 模式 // 直接处理并返回结果 const result = await this.processRequest(request) res.json(result) } } }

关键点

  1. GET 请求建立 SSE 通道并保持连接
  2. POST 请求时检查是否有活跃的 SSE 连接
  3. 如果有 SSE 连接,响应通过 SSE 推送(Streamable HTTP)
  4. 如果没有 SSE 连接,响应直接返回(传统 HTTP)

3.2 你的代码中的体现

让我们看看你的 NewsNow 项目中的实现:

server/api/mcp.post.ts - 处理 POST 请求

typescript
展开代码
export default defineEventHandler(async (event) => { const req = event.node.req const res = event.node.res const server = getServer() // 关键:兼容不同客户端的 Accept 头 const accept = req.headers["accept"] || req.headers["Accept"] if (typeof accept !== "string" || !(/application\/json/i.test(accept) && /text\/event-stream/i.test(accept))) { // 如果客户端没有声明支持 SSE,就补上 req.headers["accept"] = "application/json, text/event-stream" } // 创建传输层 const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: undefined }) // 连接 MCP 服务器 await server.connect(transport) // 让 SDK 自动判断使用哪种模式 await transport.handleRequest(req, res, await readBody(event)) return res })

server/api/mcp.get.ts - 处理 GET 请求(建立 SSE)

typescript
展开代码
export default defineEventHandler(async (event) => { const req = event.node.req const res = event.node.res const server = getServer() const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: undefined }) await server.connect(transport) // 注意:GET 请求不传 body await transport.handleRequest(req, res) return res })

3.3 工作流程对比

Cursor 使用 HTTP 模式时

展开代码
1. Cursor 发送: POST /api/mcp Body: {"jsonrpc":"2.0","id":1,"method":"tools/list"} 2. Nitro 路由到 mcp.post.ts 3. StreamableHTTPServerTransport.handleRequest() → 检测到 POST 且无活跃 SSE → 进入传统 HTTP 模式 4. 处理 JSON-RPC 请求 → 调用 server.tool() 注册的函数 → 返回结果 5. 直接响应: Status: 200 Body: {"jsonrpc":"2.0","id":1,"result":{...}}

Inspector 使用 Streamable HTTP 模式时

展开代码
1. Inspector 建立 SSE: GET /api/mcp 2. Nitro 路由到 mcp.get.ts → StreamableHTTPServerTransport 建立 SSE 通道 → 响应头: Content-Type: text/event-stream → 连接保持打开 3. Inspector 发送请求: POST /api/mcp Body: {"jsonrpc":"2.0","id":1,"method":"tools/list"} 4. Nitro 路由到 mcp.post.ts → StreamableHTTPServerTransport.handleRequest() → 检测到活跃的 SSE 连接 → 进入 Streamable HTTP 模式 5. 处理 JSON-RPC 请求 → 调用 server.tool() 注册的函数 6. 不直接返回,而是: POST 响应: Status: 202 Accepted (空 body) SSE 推送: data: {"jsonrpc":"2.0","id":1,"result":{...}} 7. Inspector 通过 SSE 通道收到结果

四、为什么需要 Accept 头的兼容处理?

你可能注意到代码中有这段"魔法":

typescript
展开代码
const accept = req.headers["accept"] if (!(/application\/json/i.test(accept) && /text\/event-stream/i.test(accept))) { req.headers["accept"] = "application/json, text/event-stream" }

4.1 Accept 头的作用

HTTP Accept 头告诉服务端"客户端能接受什么格式的响应":

http
展开代码
Accept: application/json

→ 我只接受 JSON

http
展开代码
Accept: application/json, text/event-stream

→ 我既接受 JSON,也接受 SSE 流

4.2 MCP SDK 的严格检查

StreamableHTTPServerTransport 内部会检查 Accept 头:

typescript
展开代码
// SDK 内部逻辑(简化) if (!acceptHeader.includes('application/json') || !acceptHeader.includes('text/event-stream')) { return res.status(406).send('Not Acceptable') }

为什么要这么严格?

  • 确保客户端能正确处理 SSE 响应
  • 避免不支持 SSE 的客户端收到流式数据后崩溃

4.3 兼容性问题

但实际使用中会遇到问题:

  • Cursor 发送的 Accept 可能只有 application/json
  • curl 测试时默认 Accept 是 */*
  • 某些旧版客户端不知道要声明 text/event-stream

如果严格按 SDK 要求,这些客户端都会收到 406 错误!

4.4 解决方案

在服务端"宽松处理",自动补全 Accept 头:

typescript
展开代码
// 如果客户端没有声明支持 SSE,我们替它声明 if (!accept.includes('text/event-stream')) { req.headers["accept"] = "application/json, text/event-stream" }

效果

  • Cursor 发送 Accept: application/json → 服务端改成 application/json, text/event-stream
  • SDK 检查通过 ✅
  • 但因为没有建立 SSE 连接,实际还是走 HTTP 模式
  • 两全其美!

五、Node.js / Nitro 框架中的请求处理

5.1 Nitro 是什么?

Nitro 是一个服务端框架(Nuxt 3 的底层),特点:

  • 基于文件路由:server/api/xxx.ts 自动成为 /api/xxx 端点
  • 支持多种部署目标:Node.js、Cloudflare Workers、Vercel 等
  • 提供 defineEventHandler 封装请求处理

5.2 文件路由工作原理

你的项目结构:

展开代码
server/ api/ mcp.post.ts → POST /api/mcp mcp.get.ts → GET /api/mcp

Nitro 会自动:

  1. 扫描 server/api/ 目录
  2. 根据文件名生成路由
  3. 根据文件名后缀(.get.ts / .post.ts)绑定 HTTP 方法

等价于 Express 中的

javascript
展开代码
app.get('/api/mcp', (req, res) => { ... }) app.post('/api/mcp', (req, res) => { ... })

5.3 defineEventHandler 解析

typescript
展开代码
export default defineEventHandler(async (event) => { const req = event.node.req // 原生 Node.js IncomingMessage const res = event.node.res // 原生 Node.js ServerResponse // 读取请求体 const body = await readBody(event) // 直接操作响应 res.setHeader('Content-Type', 'application/json') res.end(JSON.stringify({...})) return res })

event 对象提供的能力

  • event.node.req/res - 访问原生 Node.js 对象
  • readBody(event) - 解析请求体(自动处理 JSON/表单)
  • getHeader(event, 'xxx') - 获取请求头
  • setResponseHeader(event, 'xxx', 'yyy') - 设置响应头

5.4 为什么要访问 event.node.req/res

MCP SDK 需要原生的 Node.js 请求/响应对象:

typescript
展开代码
await transport.handleRequest(req, res, body)

这是因为 SDK 要直接操作:

  • 设置响应头(SSE 需要特殊的 Content-Type
  • 保持连接打开(SSE 长连接)
  • 写入流数据(res.write()

Nitro 的抽象层无法满足这些底层需求,所以必须"穿透"到 Node.js 层。


六、SSE (Server-Sent Events) 深入理解

6.1 SSE 是什么?

SSE 是 HTML5 标准,允许服务端向客户端推送数据:

HTTP 响应示例

http
展开代码
HTTP/1.1 200 OK Content-Type: text/event-stream Cache-Control: no-cache Connection: keep-alive data: {"message": "hello"} data: {"message": "world"} : this is a comment data: multi-line data: message

关键特性

  • 基于 HTTP 长连接
  • 服务端可以持续推送
  • 客户端用 EventSource API 接收
  • 自动重连机制

6.2 SSE 的格式规范

每条消息由多行组成,以空行分隔:

展开代码
field: value\n field: value\n \n

标准字段

  • data: - 消息内容(必须)
  • id: - 消息 ID(可选,用于重连时续传)
  • event: - 事件类型(可选,默认 "message")
  • : 开头 - 注释(可用于心跳)

示例

展开代码
id: 1 event: news data: {"title": "Breaking news"} : heartbeat id: 2 data: {"title": "Another news"} data: {"description": "Details here"}

6.3 为什么 POST 响应是 202?

在 Streamable HTTP 模式下:

typescript
展开代码
// POST 请求收到后 res.status(202).end() // 202 Accepted

HTTP 202 Accepted 的含义

"我已经收到你的请求,正在处理,但现在不给你结果"

这完美符合 Streamable HTTP 的语义:

  • POST 只是"发送"请求
  • 真正的响应稍后通过 SSE 推送
  • 客户端不应该等待 POST 响应的 body

6.4 JavaScript 中使用 SSE

客户端代码示例

javascript
展开代码
// 建立 SSE 连接 const eventSource = new EventSource('http://107.173.199.53:9044/api/mcp') // 监听消息 eventSource.onmessage = (event) => { const data = JSON.parse(event.data) console.log('Received:', data) } // 错误处理 eventSource.onerror = (error) => { console.error('SSE error:', error) eventSource.close() } // 发送请求(需要另外的 fetch) fetch('http://107.173.199.53:9044/api/mcp', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ jsonrpc: '2.0', id: 1, method: 'tools/list' }) }) // 响应会通过上面的 eventSource.onmessage 收到

七、实战:手动测试两种模式

7.1 测试 HTTP 模式(Cursor 使用的方式)

单次请求-响应

bash
展开代码
curl -X POST http://107.173.199.53:9044/api/mcp \ -H "Content-Type: application/json" \ -H "Accept: application/json" \ -d '{ "jsonrpc": "2.0", "id": 1, "method": "tools/list", "params": {} }'

预期响应

json
展开代码
{ "jsonrpc": "2.0", "id": 1, "result": { "tools": [ { "name": "get_hotest_latest_news", "description": "...", "inputSchema": {...} } ] } }

7.2 测试 Streamable HTTP 模式(Inspector 使用的方式)

终端 1:建立 SSE 连接

bash
展开代码
curl -N http://107.173.199.53:9044/api/mcp # 连接保持打开,等待事件...

终端 2:发送 POST 请求

bash
展开代码
curl -X POST http://107.173.199.53:9044/api/mcp \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "id": 1, "method": "tools/list" }'

预期

  • 终端 2 收到 202 Accepted
  • 终端 1 收到 SSE 推送:
    展开代码
    data: {"jsonrpc":"2.0","id":1,"result":{...}}

7.3 调试技巧

查看 HTTP 详细信息

bash
展开代码
curl -v http://107.173.199.53:9044/api/mcp

持续监听 SSE(带时间戳)

bash
展开代码
curl -N http://107.173.199.53:9044/api/mcp | \ while IFS= read -r line; do echo "[$(date +%H:%M:%S)] $line" done

模拟 Inspector 的完整流程

bash
展开代码
# 1. 在后台建立 SSE curl -N http://107.173.199.53:9044/api/mcp > sse_output.txt & SSE_PID=$! # 2. 等待连接建立 sleep 1 # 3. 发送 initialize curl -X POST http://107.173.199.53:9044/api/mcp \ -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}}}' # 4. 查看 SSE 输出 sleep 1 cat sse_output.txt # 5. 清理 kill $SSE_PID

八、架构优势与设计思考

8.1 为什么同一个 Transport 支持两种模式?

设计理念:协议层与传输层解耦

展开代码
┌─────────────────────────────────────────┐ │ MCP 协议层 │ │ (initialize, tools/list, tools/call) │ └─────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────┐ │ StreamableHTTPServerTransport │ │ (智能判断使用 HTTP 还是 SSE) │ └─────────────────────────────────────────┘ ↓ ┌───────────┴───────────┐ ↓ ↓ ┌─────────┐ ┌─────────┐ │ HTTP │ │ SSE │ │ 模式 │ │ 模式 │ └─────────┘ └─────────┘

好处

  • 业务代码无需关心传输细节
  • 一套代码支持多种客户端
  • 客户端可以自由选择模式
  • 未来可以轻松扩展新的传输方式(如 WebSocket)

8.2 与传统 REST API 的对比

传统 REST

展开代码
POST /api/news/zhihu?count=10 → 返回新闻列表 不同的功能需要不同的端点: POST /api/news POST /api/weather POST /api/translate

MCP 方式

展开代码
POST /api/mcp {"method": "get_hotest_latest_news", "params": {"id": "zhihu"}} POST /api/mcp {"method": "get_weather", "params": {...}} POST /api/mcp {"method": "translate", "params": {...}} 所有功能共用一个端点,通过 method 区分

优势

  • 统一的错误处理
  • 统一的认证机制
  • 易于添加新功能(注册新 tool)
  • 天然支持批量请求

8.3 性能考虑

HTTP 模式的开销

  • 每次请求建立新连接(TCP 握手)
  • HTTP 头部传输(Cookie、User-Agent 等)
  • 适合低频调用

Streamable HTTP 模式的优势

  • 连接复用(一次握手,多次请求)
  • 减少头部重复传输
  • 适合高频调用或需要推送的场景

在 NewsNow 中的选择

  • Cursor:低频工具调用 → HTTP 模式足够
  • Inspector:调试时频繁测试 → Streamable HTTP 更高效

九、常见问题与进阶话题

9.1 如果 SSE 连接断开会发生什么?

MCP SDK 会:

  1. 检测到连接断开(res.on('close') 事件)
  2. 清理内部状态
  3. 后续 POST 请求自动降级到 HTTP 模式

代码体现

typescript
展开代码
res.on("close", () => { transport.close() // 清理 SSE 状态 server.close() // 断开 MCP 连接 })

9.2 是否可以同时建立多个 SSE 连接?

可以,每个 SSE 连接对应一个独立的会话:

typescript
展开代码
const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: undefined // 自动生成唯一 session ID })

多个客户端连接时:

  • 客户端 A: 建立 SSE-A,发送 POST-A1, POST-A2
  • 客户端 B: 建立 SSE-B,发送 POST-B1, POST-B2
  • 每个 POST 的响应路由到对应的 SSE 通道

9.3 为什么不用 WebSocket?

WebSocket vs SSE

特性SSEWebSocket
双向通信❌ 只能服务端→客户端✅ 双向
协议HTTP需要升级到 ws://
防火墙穿透✅ 标准 HTTP⚠️ 可能被拦截
实现复杂度简单较复杂
自动重连✅ 浏览器内置❌ 需要手动实现

MCP 选择 SSE 的原因

  • MCP 的主要通信是"客户端请求 + 服务端响应"
  • POST 已经解决了客户端→服务端的通道
  • SSE 只需解决服务端→客户端的推送
  • 更简单、更兼容

9.4 在生产环境中的注意事项

反向代理配置(Nginx)

nginx
展开代码
location /api/mcp { proxy_pass http://backend:4444; # 关键:SSE 需要禁用缓冲 proxy_buffering off; proxy_cache off; # 保持长连接 proxy_read_timeout 3600s; proxy_connect_timeout 75s; # 传递必要的头 proxy_set_header Connection ''; proxy_http_version 1.1; chunked_transfer_encoding off; }

Docker 部署

yaml
展开代码
# docker-compose.yml services: newsnow: build: . ports: - "9044:4444" environment: - NODE_ENV=production # 确保不设置请求超时 - NITRO_TIMEOUT=0

十、总结

10.1 核心要点回顾

  1. MCP 是协议,不是传输

    • 定义消息格式(JSON-RPC)
    • 不限制如何传输
  2. StreamableHTTPServerTransport 的智能

    • GET 请求 → 建立 SSE 通道
    • POST + 无 SSE → HTTP 模式
    • POST + 有 SSE → Streamable HTTP 模式
  3. 一套代码,两种模式

    • Cursor 只发 POST → 自动 HTTP 模式
    • Inspector 先 GET 再 POST → 自动 Streamable HTTP 模式
  4. Accept 头的兼容性处理

    • 客户端可能不声明支持 SSE
    • 服务端宽容处理,自动补全
    • 既满足 SDK 检查,又兼容旧客户端

10.2 技术栈总结

展开代码
┌─────────────────────────────────────────┐ │ Cursor / Claude Desktop / Inspector │ ← 客户端 └─────────────────────────────────────────┘ ↓ HTTP / Streamable HTTP ↓ ┌─────────────────────────────────────────┐ │ Nitro (defineEventHandler) │ ← Web 框架 │ - mcp.get.ts → GET /api/mcp │ │ - mcp.post.ts → POST /api/mcp │ └─────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────┐ │ @modelcontextprotocol/sdk │ ← MCP 实现 │ - StreamableHTTPServerTransport │ │ - McpServer │ └─────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────┐ │ 业务逻辑 (getServer()) │ ← 你的代码 │ - server.tool("get_hotest_latest_news")│ │ - 调用 /api/s?id=xxx │ └─────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────┐ │ 数据源 (server/sources/*.ts) │ ← 爬虫逻辑 │ - zhihu.ts, weibo.ts, ... │ └─────────────────────────────────────────┘

10.3 学习路径建议

如果你想深入理解这套技术栈:

  1. 基础

    • JSON-RPC 协议规范
    • HTTP 状态码(200, 202, 406)
    • Node.js req/res 对象
  2. 进阶

    • SSE (Server-Sent Events) 规范
    • HTTP 长连接 vs 短连接
    • Nitro 框架文档
  3. 实战

    • 阅读 @modelcontextprotocol/sdk 源码
    • 用 Wireshark 抓包分析 HTTP vs SSE
    • 尝试实现一个简单的 SSE 服务器

10.4 扩展思考

这种"一个接口多种模式"的设计在其他场景也很有用:

  • GraphQL Subscriptions: HTTP 查询 + WebSocket 订阅
  • gRPC-Web: 同时支持 Unary RPC 和 Server Streaming
  • WebRTC: 先 HTTP 交换 SDP,再 P2P 传输

核心思想都是:用最合适的协议完成特定任务,而不是强行统一


参考资源


希望这篇文章帮你理解了"一个接口同时支持 HTTP 和 Streamable HTTP"的魔法!

如有问题或想深入讨论某个话题,欢迎交流! 🚀

如果对你有用的话,可以打赏哦
打赏
ali pay
wechat pay

本文作者:Dong

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 CC BY-NC。本作品采用《知识共享署名-非商业性使用 4.0 国际许可协议》进行许可。您可以在非商业用途下自由转载和修改,但必须注明出处并提供原作者链接。 许可协议。转载请注明出处!