为什么当使用“Transfer-Encoding”传输 HTTP 时,我在浏览器中看到的块大小为文本:“chunked”?

问题描述 投票:0回答:1

我正在尝试使用“Transfer-Encoding”:“chunked”来传输 HTTP。

这是 Deno 的代码 (

deno run -A --watch main.ts
):

function generateStream(): ReadableStream<Uint8Array> {
    let count = 0;
    let controller: ReadableStreamDefaultController<Uint8Array>;
    const interval = setInterval(() => {
        if (count > 3) {
            controller.close();
            clearInterval(interval);
        } else {
            const data = count < 3 ? `chunk ${count}` : "";
            count += 1;
            const size = data.length.toString(16);
            const raw = new Uint8Array([
                ...new TextEncoder().encode(size),
                0x0d,
                0x0a,
                ...new TextEncoder().encode(data),
                0x0d,
                0x0a,
            ]);
            controller.enqueue(raw);
            console.log(`sent: ${count}: ${raw}`);
        }
    }, 1000);

    return new ReadableStream({
        start(controller_) {
            controller = controller_;
        },
        cancel() {
            clearInterval(interval);
        },
    });
}

async function handler(req: Request): Promise<Response> {
    const stream = generateStream();
    return new Response(stream, {
        status: 200,
        headers: {
            "Content-Type": "text/plain",
            "Transfer-Encoding": "chunked",
            "X-Content-Type-Options": "nosniff",
        },
    });
}

await Deno.serve({ port: 8000 }, handler);

当我卷曲或使用 Chrome 时,服务器打印:

sent: 1: 55,13,10,99,104,117,110,107,32,48,13,10
sent: 2: 55,13,10,99,104,117,110,107,32,49,13,10
sent: 3: 55,13,10,99,104,117,110,107,32,50,13,10
sent: 4: 48,13,10,13,10

服务器似乎根据标准正确发送了所有内容。

视觉流式传输“有点”适用于 Chrome 和 Firefox,但不适用于 Safari。

我假设块长度必须从浏览器输出中删除,因为它们是编码的一部分。

更新:

为了清楚起见,我在 Go 中实现了它,但我仍然看到了长度。

package main

import (
    "fmt"
    "log"
    "net/http"
    "time"
)

func streamHandler(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "text/plain")
    w.Header().Set("Transfer-Encoding", "chunked")
    w.Header().Set("X-Content-Type-Options", "nosniff")

    w.(http.Flusher).Flush()

    messages := []string{
        "This is the first chunk of text.",
        "Here's another piece of the stream.",
        "And the final message in this example.",
    }

    for _, msg := range messages {
        fmt.Fprintf(w, "%x\r\n%s\r\n", len(msg), msg)
        w.(http.Flusher).Flush()
        time.Sleep(1 * time.Second)
    }
    fmt.Fprint(w, "0\r\n\r\n")
}

func main() {
    http.HandleFunc("/", streamHandler)
    fmt.Println("listening on :8000...")
    log.Fatal(http.ListenAndServe(":8000", nil))
}
http streaming deno
1个回答
0
投票

当使用“Transfer-Encoding”:“chunked”传输 HTTP 时,为什么我在浏览器中看到块大小为文本?

Deno.serve
是一个高级API - 当响应主体是流时,会自动处理块编码(包括设置标头
Transfer-Encoding: chunked
)。

因此,简而言之,您的手动编码将成为每个块内容的一部分,然后 Deno 会再次自动对这些块进行编码。使用

Deno.serve
API 时,无法选择退出这种流式响应行为。

这种自动行为的存在是因为……

在 Deno 中使用 HTTP 服务器 API 时,HTTP/2 支持是“自动”的。您只需要创建您的服务器,服务器将无缝处理 HTTP/1 或 HTTP/2 请求。

🔗https://docs.deno.com/runtime/manual/runtime/http_server_apis/#http%2F2-support

…还有…

HTTP/2 不允许使用除 HTTP/2 特定之外的所有 Transfer-Encoding 标头:

"trailers"
。 HTTP 2 提供了比分块传输更有效的数据流机制,并禁止使用标头。

🔗 https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Transfer-Encoding

如果您想实现自己的手动块编码,则需要使用 Deno 的低级网络 API

有关更多信息,请参阅手册中的HTTP 服务器 API

© www.soinside.com 2019 - 2024. All rights reserved.