You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Fetch请求与WebSocket速度对比实测:WebSocket为何比HTTP更快?

问题描述

我使用Fetch和WebSocket传输相同的数据时,出现了以下情况:

  • HTTP传输约200 MB数据耗时29秒
  • WebSocket传输约200 MB数据仅耗时6秒

疑问

为什么WebSocket的传输速度比HTTP更快?是与编码、底层技术原理还是其他因素有关?


测试代码

Fetch 实现代码

async function postData(url = '', data) {
        const response = await fetch(url, {
            method: 'POST',
            mode: 'no-cors',
            cache: 'no-cache',
            credentials: 'same-origin',
            headers: {
                'Content-Type': 'application/octet-stream'
            },
            redirect: 'follow',
            referrerPolicy: 'no-referrer',
            body: data
        });
        return response; //.arrayBuffer();
    }

    postData('http://localhost:3800/buffer', arrU8)
        .then(data => {
            console.log(data);
        });

其中arrU8是长度为185578200的Uint8Array类型数据。

WebSocket 实现代码

function connect() {
        return new Promise(function (resolve, reject) {
            var ws = new WebSocket('ws://127.0.0.1:8081/echo');
            ws.onopen = function () {
                resolve(ws);
            };
            ws.onerror = function (err) {
                reject(err);
            };
            ws.onclose = function (evt) {
                console.log("CLOSE SOCKET", new Date().toLocaleString());
            };
            ws.onmessage = function (evt) {
                console.log("RESPONSE SOCKET: " + "RECEIVED" /* evt.data */, new Date().toLocaleString());
            };
        });
    }

    connect().then(function (ws) {
        // onopen
        ws.binaryType = 'arraybuffer';
        ws.send(arrU8);
        ws.close();
    }).catch(function (err) {
        // onerror
        console.log("ERROR: " + evt.data, new Date().toLocaleString());
    });

服务端Go实现代码

HTTP 服务端代码

func process(w http.ResponseWriter, r *http.Request) {

    if r.URL.Path != "/buffer" {
        http.Error(w, "404 not found.", http.StatusNotFound)
        return
    }

    switch r.Method {
    case "GET":

        fmt.Fprintf(w, "GET request is received: %s \n", r.URL)
    case "POST":

        body, err := ioutil.ReadAll(r.Body)
        if err != nil {
            http.Error(w, err.Error(), http.StatusInternalServerError)
            return
        }
        log.Println("Data length received = ", len(body))

        fmt.Fprintf(w, "Data length = %v \n", len(body))

    default:
        fmt.Fprintf(w, "Sorry, only GET and POST methods are supported.")
    }
}

WebSocket 服务端代码

package main

import (
    "flag"
    "log"
    "net/http"
    "text/template"

    "github.com/gorilla/websocket"
)

var addr = flag.String("addr", "localhost:8081", "http service address")
var upgrader = websocket.Upgrader{} // use default options
func main() {

    log.Println("Launching WebSocket server...", *addr)
    flag.Parse()
    log.SetFlags(log.LstdFlags | log.Lmicroseconds)
    http.HandleFunc("/echo", echo)
    http.HandleFunc("/", home)
    log.Fatal(http.ListenAndServe(*addr, nil))
}

func echo(w http.ResponseWriter, r *http.Request) {

    // To fix 403 error temporarily. It's unsafe:
    upgrader.CheckOrigin = func(r *http.Request) bool { return true }

    c, err := upgrader.Upgrade(w, r, nil)
    if err != nil {
        log.Print("upgrade:", err)
        return
    }
    defer c.Close()
    for {
        mt, message, err := c.ReadMessage()
        if err != nil {
            log.Println("read:", err)
            break
        }
        log.Println("recv: message type:", mt)
        log.Printf("recv: bytes count: %v", len(message))
        // // // Disable echo and log
        // log.Printf("recv: %s", message)
        // err = c.WriteMessage(mt, message)
        // if err != nil {
        //  log.Println("write:", err)
        //  break
        // }
    }
}

func home(w http.ResponseWriter, r *http.Request) {
    homeTemplate.Execute(w, "ws://"+r.Host+"/echo")
}

速度差异原因

  1. 连接与协议开销差异
    WebSocket仅在建立连接时进行一次HTTP握手,后续复用同一个TCP连接传输数据,仅需2~10字节的轻量帧头,没有额外的HTTP头开销。而HTTP/1.x每个请求都需要携带完整的请求头(通常几百字节以上),就算开启Keep-Alive复用TCP连接,每次请求的头开销也会累积,大体积数据传输时有效载荷占比远低于WebSocket。

  2. 传输模式差异
    HTTP是半双工的请求-响应模式,客户端发送请求后必须等待服务端返回响应才能进行后续操作,链路存在闲置空窗期,利用率低。WebSocket是全双工传输,连接建立后两端可以同时收发数据,不需要等待响应,链路利用率更高。

  3. 测试代码的额外影响
    你在Fetch配置中使用了mode: 'no-cors',该模式会触发浏览器的跨域限制逻辑,如果服务端没有正确配置CORS,还会产生额外的OPTIONS预检请求开销,进一步拖慢传输速度。


内容的提问来源于stack exchange,提问作者Babak irannezhad

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 04:54:05