在调用 GetRequestStream(或 BeginGetRequestStream)之前设置 ContentLength 属性,然后向该流写入更少的字节。如果您在获得请求流后尝试设置 ContentLength ,则会抛出异常。如果您不设置 ContentLength,HttpWebRequest 将缓冲标头,直到流关闭,以便它可以适当地设置 ContentLength(或者,您可以使用 SendChunked,但这对您不起作用)。如果您想最大程度地控制它,请手动创建一个或两个畸形请求,然后打开一个到服务器上端口 80 的套接字并将请求写入 TCP 流,然后读取响应并检查连接是否已关闭.
然而:我不认为这个测试是一个好主意。这是问题所在:
客户端向服务器发送请求。它声称内容将是 100 字节。然后它发送 90 个字节,然后停止发送,使连接保持打开状态。服务器读取 90 个字节,然后等待其余的,因为客户端说将发送 100 个字节。现在,客户端发送第二个请求。服务器将如何处理新请求的前 10 个字节?
答案是服务器会假设这些字节是前一个请求的一部分并将它们视为这样,然后在开始后 10 个字节开始读取“新”请求,这显然会导致格式错误的标头。服务器不喜欢这样,所以它会发送一个 4xx 错误,然后它会关闭连接。它关闭连接的原因是因为它现在无法知道发送给它的数据意味着什么,也无法恢复。此外,连接的关闭不会是优雅的,它会很突然,并且另一端的 HttpWebRequest 正在提交第二个请求(或者第三个或第四个,如果他们排队)将抛出一个 WebException 说底层连接已关闭,让您猜测原因。
同样的行为是导致连接以 Expect 100-continue 标头关闭的原因,并且服务器返回 100-continue 后跟 4xx,例如当需要 Auth 时。即使它拒绝了请求,它仍然必须假设下一个字节是同一个请求的一部分,因为它已经承诺通过发送 100-continue 来接收这些字节。如果它不会为该请求提供服务,或者如果客户端想要取消请求并提交一个新请求(可能带有身份验证凭据),那么它必须关闭连接并打开一个新请求。
最后,使用 TCP 从网络流中测试 EndOfStreamException 对我来说根本没有任何意义。TCP 不会标记流的“结束”,它只是在将数据写入套接字时继续发送数据。它没有“EOF”,也无法检测数据是否已全部传输,除非您知道预期有多少数据。除非连接关闭,否则 TCP 的流实际上并没有“结束”,在这种情况下,您将获得 WebException 或 SocketException,具体取决于您在堆栈中的操作位置。协议中的任何传输错误都在winsock中处理。如果不再发送数据,则连接的一端最终将向另一端发送保持活动状态,以确保连接实际上仍处于打开状态,并且一台主机不会直接丢弃它。如果 keepalive 超时,连接将被关闭,并且您下次尝试从中读取时可能会收到 WebException。鉴于所有这些是如何工作的,我只是看不出你将如何从这个测试中获得任何价值。您最好只发送格式错误的请求并确保相应地处理错误并将适当的 4xx 消息发送回客户端并正确关闭连接。