← 项目展示

请求方式对比 Demo

多卡片对比 XHR、Fetch、SSE、WebSocket、WebTransport、HTTP/2 Push、JSONP、Beacon、Image 等请求技术与单次/流式/长轮询/全双工/只发不收场景。

请求方式对比 Demo
在线预览
全屏打开

简介

这个 demo 用「技术 × 业务场景」两个维度对比浏览器中常见的数据请求方式:

  • 技术维度:XMLHttpRequest、Fetch、EventSource、WebSocket、WebTransport、HTTP/2 Push、JSONP、Beacon、Image
  • 场景维度:单次请求、流式接收、长轮询、全双工、只发不收

页面顶部有对照矩阵,下方卡片按场景分组;WebTransport / HTTP/2 Push 在本机 Express 环境下以能力探测为主(诚实展示不可用原因)。

卡片说明

单次请求

卡片关键 API
XHR 单次new XMLHttpRequest() + onload
Fetch 单次fetch().then(r => r.json())
JSONP 单次动态 <script> 注入 + 全局回调

流式接收

卡片关键 API
XHR 流式合理设计text/"" + 服务端一次 ~2KB prelude + \n 分帧(?design=1)+ readyState=3 轮询;非「假流」
XHR BlobresponseType=blobprogress.loaded 会涨,但 xhr.response 在结束前为 null不能提前读正文
Fetch 流式response.body.getReader() + TextDecoder
SSEnew EventSource() + onmessage
iframe 流式Forever Frame:隐藏 iframe 加载 chunked HTML,逐步执行 <script>parent.cb(word)</script>
HTTP/2 Push已过时:探测 Link: rel=preload 替代方案与 Performance push timing(通常为 0)

长轮询

客户端收到响应后立即发起下一次请求,模拟服务器推送(SSE 出现前的常见方案)。

卡片风格
XHR 长轮询回调递归
Fetch 长轮询async/await 循环

全双工 — WebSocket / WebTransport

卡片说明
WebSocket本机可用:握手后逐词 push
WebTransport需 HTTPS + HTTP/3;api2 为 HTTP/1.1 Express,卡片做 typeof WebTransport + 连接尝试并展示失败原因

只发不收 — Beacon / Image

卡片关键 API数据放哪能读响应吗
Beaconnavigator.sendBeacon()POST body否(只知是否入队)
Image 像素new Image(); img.src = urlURL query否(只有 onload/onerror;响应是 1×1 GIF)

img 像素点是更老的埋点手段:兼容好、只能 GET、有长度限制;sendBeacon 更适合卸载时可靠上报且可 POST。

页面如何看懂数据效果

每张卡片分三层:

  1. 实时数据区:真正展示收到的内容
    • 单次 / JSONP / Beacon → 完整 JSON payload 块
    • 流式 / WebSocket → 每个词以 chip 动画逐个弹出,最新一块高亮
    • 长轮询 → 等待条 + 每轮 #seq 词 列表(挂起等待时有滑动进度条)
  2. 事件时间线+Nms 时间戳日志,记录「请求开始 / 收到 chunk / 等待挂起 / 完成」
  3. 底部指标:耗时、块/事件数、字节数(运行中实时刷新)

后端接口

接口挂载在 GET /api/demo/compare/...,默认走本地 mock(无需 API Key)。顶部切换「LLM」后,带 X-Source: llm?source=llm(EventSource / JSONP / iframe / WS)的 once / stream / sse / jsonp / iframe-stream / ws 会代理 DashScope;未配置 DASHSCOPE_API_KEY 时返回 503。长轮询与 Beacon / pixel 始终 mock。

路径方法说明
/onceGET单次 JSON;LLM 时汇总完整回复
/streamGET分块 plain-text,?delay=ms;LLM 时按 token 写出
/sseGETtext/event-stream;LLM 用 ?source=llm
/iframe-streamGETForever Frame:chunked HTML + <script> 回调
/long-pollGET延迟 1.5s 后返回,?seq=N(始终 mock)
/jsonpGET?callback=cb;LLM 用 ?source=llm
/beaconPOST204 No Content
/pixelGET1×1 GIF(<img src> 埋点)
/capabilitiesGETWebTransport / H2 Push / LLM 配置说明
/h2-pushGETLink: rel=preload 示意(非真 Push)
/wsWS UpgradeWebSocket,逐词 push;LLM 用 ?source=llm

如何测试验证

  1. 打开 demo,点「▶ 全部运行」,观察各卡片并发执行。
  2. 对比「XHR 流式」和「Fetch 流式」:两者访问同一 /stream 接口,但 API 完全不同。
  3. 对比「XHR 长轮询」和「Fetch 长轮询」:观察两者的代码风格差异(回调 vs async/await),耗时相近。
  4. 拉大延迟到 150ms,再跑流式和 SSE,观察块数/耗时变化。
  5. Network 面板可见:/stream 为 Transfer-Encoding: chunked;/sse 为 text/event-stream;/ws 为 101 Switching Protocols。

相关规范与文档