为了账号安全,请及时绑定邮箱和手机立即绑定

分块流响应不正确

分块流响应不正确

C#
眼眸繁星 2022-01-09 16:26:31
抱歉,标题这么模糊,我真的不知道该问题的标题是什么。基本上,当我得到传输编码所告诉的分块流时,我然后执行以下代码:private IEnumerable<byte[]> ReceiveMessageBodyChunked() {    readChunk:    #region Read a line from the Stream which should be a Block Length (Chunk Body Length)    string blockLength = _receiverHelper.ReadLine();    #endregion    #region If the end of the block is reached, re-read from the stream    if (blockLength == Http.NewLine) {        goto readChunk;    }    #endregion    #region Trim it so it should end up with JUST the number    blockLength = blockLength.Trim(' ', '\r', '\n');    #endregion    #region If the end of the message body is reached    if (blockLength == string.Empty) {        yield break;    }    #endregion    int blockLengthInt = 0;    #region Convert the Block Length String to an Int32 base16 (hex)    try {        blockLengthInt = Convert.ToInt32(blockLength, 16);    } catch (Exception ex) {        if (ex is FormatException || ex is OverflowException) {            throw new Exception(string.Format(ExceptionValues.HttpException_WrongChunkedBlockLength, blockLength), ex);        }        throw;    }    #endregion    // If the end of the message body is reached.    if (blockLengthInt == 0) {        yield break;    }    byte[] buffer = new byte[blockLengthInt];    int totalBytesRead = 0;    while (totalBytesRead != blockLengthInt) {        int length = blockLengthInt - totalBytesRead;        if (bytesRead == 0) {            WaitData();            continue;        }        totalBytesRead += bytesRead;        yield return buffer;    }    goto readChunk;}这样做是从应该是块长度的流中读取 1 行数据,在这里和那里进行一些检查,但最终将其转换为 Int32 Radix16 整数。从那里它基本上创建了一个 int32 的字节缓冲区作为它的长度大小。然后它只是继续从流中读取,直到它读取与我们转换的 Int32 相同的数量。这很好用,但是,无论出于何种原因,它在最后一次阅读时响应不正确。它将读取确切的字节数,因为块长度非常好,并且我期望的所有数据都被读取。但它也在再次读取另一小块数据,这些数据在最后已经读取,导致我们可以说从ASWELL<!DOCTYPE html>到</html>ASWELL 的所有数据作为来自内部某处的一些数据<form>等这是发生的事情的一个例子:如您所见,突出显示的红色文本不应该从阅读中返回!它应该在 结束</html>。为什么 Chunk's Length 对我说谎,我怎样才能找到合适的尺寸来阅读?
查看完整描述

1 回答

?
一只萌萌小番薯

TA贡献1795条经验 获得超7个赞

我不熟悉 C# 但如果我正确理解了您的代码和ReadC# 中的语义(这似乎与readC 中的相似),那么问题是您一次又一次地使用相同的缓冲区而没有先重置它:


byte[] buffer = new byte[blockLengthInt];

int totalBytesRead = 0;

while (totalBytesRead != blockLengthInt) {

    int length = blockLengthInt - totalBytesRead;

    int bytesRead = _receiverHelper.HasData ? _receiverHelper.Read(buffer, 0, length) : _request.ClientStream.Read(buffer, 0, length);

    ...

    totalBytesRead += bytesRead;

    ...

    yield return buffer;

}

举例说明这里出了什么问题:假设块大小为 10,您读取的内容是0123456789,第一次读取将返回 6 个字节,第二次读取剩余的 4 个字节。在这种情况下,您的缓冲区将012345在第一次读取567845之后和第二次读取之后。这些45在缓冲区末尾量与上一读,因为你只是取代了缓冲区中的第4个字节,但保留了休息。


奇怪的是,如果我将请求交给另一个 TCPStream 代理(127.0.0.1:8888 作为代理,它是提琴手),它工作得非常好......


Fiddler 是一个代理,可能会改变响应的传输方式。例如,它可能使用Content-length分块编码而不是分块编码,或者它可能使用较小的块,以便您始终在第一次读取时获得完整的块。


查看完整回答
反对 回复 2022-01-09
  • 1 回答
  • 0 关注
  • 193 浏览

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号