我正在尝试使用“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))
}
当使用“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 标头:
。 HTTP 2 提供了比分块传输更有效的数据流机制,并禁止使用标头。
"trailers"
🔗 https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Transfer-Encoding
如果您想实现自己的手动块编码,则需要使用 Deno 的低级网络 API。
有关更多信息,请参阅手册中的HTTP 服务器 API。