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

基于同一HTTP/2请求响应流实现全双工通信的问题排查

问题描述

我在Chrome 114客户端与ASP.NET Core 7服务器之间,尝试将单个HTTP/2请求-响应流作为全双工通信通道:客户端使用ReadableStream/WritableStream,服务器使用PipeReader/PipeWriter,目的是同时发送长请求、接收长响应。实际测试功能可用,但必须等请求完全发送完成后才能读取响应。

核心疑问:

  • 为什么客户端代码中的读取操作无法与写入操作同步打印日志?
  • 无法将fetch的duplex属性设置为"full",浏览器不识别该值。浏览器中的HTTP/2不支持全双工吗?HTTP/3是否存在同样问题?

客户端代码(JavaScript)

let writeTotal = 0;
let readTotal = 0;

const reqStream = new ReadableStream({
    pull: (controller) => {
        controller.enqueue("Yousuf is lovely!\n");
        writeTotal += 18;

        // 为什么所有写入日志先打印,之后才轮到读取日志?
        console.log("Write: " + writeTotal);
        
        if (writeTotal === 18 * 100000) {
            controller.close();
        }
    },
});

const resStream = new WritableStream({
    write: (chunk) => {
        readTotal += chunk.length;
        
        // 为什么读取日志不能和写入日志同步打印?
        console.log("Read: " + readTotal);
    }
})

const result = await fetch("https://localhost:8080/", {
    method: "POST",
    body: reqStream.pipeThrough(new TextEncoderStream()),
    duplex: 'half' // 没法设为full!
});

await result.body.pipeThrough(new TextDecoderStream()).pipeTo(resStream);

console.log("Total Written: " + writeTotal);
console.log("Total Read: " + readTotal);

服务器端代码(C#)

using System.Buffers;
using System.IO.Pipelines;
using System.Text;

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.Map("/", async (context) =>
{
    PipeReader reader = context.Request.BodyReader;
    PipeWriter writer = context.Response.BodyWriter;
    long total = 0;
    
    // 这里打印的是HTTP/2
    Console.WriteLine("New Request: " + context.Request.Protocol);
    
    while (true)
    {
        ReadResult result = await reader.ReadAsync();
        ReadOnlySequence<byte> buffer = result.Buffer;
        SequencePosition position = buffer.GetPosition(0);
        string body = Encoding.UTF8.GetString(buffer.Slice(position));
        
        Console.WriteLine("New Chunk: " + body.Length);
        Console.WriteLine(body.Substring(0, Math.Min(10, body.Length)));
        Console.WriteLine("\n");

        await writer.WriteAsync(Encoding.UTF8.GetBytes(body));

        reader.AdvanceTo(buffer.GetPosition(buffer.Length));

        total += body.Length;

        if (result.IsCompleted || result.IsCanceled || total == 18 * 100000)
        {
            Console.WriteLine("Completed? " + result.IsCompleted);
            Console.WriteLine("Canceled? " + result.IsCanceled);
            
            await reader.CompleteAsync();
            await writer.CompleteAsync();

            Console.WriteLine("\n");
            Console.WriteLine("Total: " + total);
            Console.WriteLine("\n");
            
            break;
        }
    }
});

app.Run();

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 22:53:20