调试AWS示例遇System.Net.ProtocolViolationException请求流内容长度错误
问题描述
运行AWS官网示例代码时触发错误:
System.Net.ProtocolViolationException: 'You must write ContentLength bytes to the request stream before calling [Begin]GetResponse.'
错误出现在CheckResponse方法的这一行:
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
CheckResponse完整代码:
public static void CheckResponse(HttpWebRequest request) { Console.WriteLine("\n-- CHECK RESPONCE"); // Get the response and read any body into a string, then display. Console.WriteLine(request.ContentLength); //857 using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) { if (response.StatusCode == HttpStatusCode.OK) { Console.WriteLine("\n-- HTTP call succeeded"); var responseBody = ReadResponseBody(response); if (!string.IsNullOrEmpty(responseBody)) { Console.WriteLine("\n-- Response body:"); Console.WriteLine(responseBody); } } else Console.WriteLine("\n-- HTTP call failed, status code: {0}", response.StatusCode); } }
打印request.ContentLength显示为857,但仍报错,手动设置request.ContentLength = 857也无效。调用CheckResponse的InvokeHttpRequest方法代码:
public static void InvokeHttpRequest(Uri endpointUri, string httpMethod, IDictionary<string, string> headers, string requestBody) { try { var request = ConstructWebRequest(endpointUri, httpMethod, headers); if (!string.IsNullOrEmpty(requestBody)) { var buffer = new byte[8192]; // arbitrary buffer size var requestStream = request.GetRequestStream(); using (var inputStream = new MemoryStream(Encoding.UTF8.GetBytes(requestBody))) { var bytesRead = 0; while ((bytesRead = inputStream.Read(buffer, 0, buffer.Length)) > 0) { requestStream.Write(buffer, 0, bytesRead); } } } CheckResponse(request); } catch (WebException ex) { Console.WriteLine(ex.ToString()); using (var response = ex.Response as HttpWebResponse) { if (response != null) { var errorMsg = ReadResponseBody(response); Console.WriteLine("\n-- HTTP call failed with exception '{0}', status code '{1}'", errorMsg, response.StatusCode); } } } }
解决方案
这个错误核心是请求流未被正确关闭/刷新,导致实际写入字节数和ContentLength不匹配(哪怕你看着写够了)。
具体修复步骤:
- 妥善处理请求流:把
requestStream放进using块,让它自动关闭并释放资源。当前代码里requestStream没被正确处理,写完后流可能还处于未刷新状态,服务器收不到完整字节。
修改InvokeHttpRequest中的请求体写入部分:
if (!string.IsNullOrEmpty(requestBody)) { var buffer = new byte[8192]; // 将requestStream纳入using块,自动关闭 using (var requestStream = request.GetRequestStream()) using (var inputStream = new MemoryStream(Encoding.UTF8.GetBytes(requestBody))) { int bytesRead; while ((bytesRead = inputStream.Read(buffer, 0, buffer.Length)) > 0) { requestStream.Write(buffer, 0, bytesRead); } // 手动刷新流(可选,但更保险) requestStream.Flush(); } }
- 检查
ConstructWebRequest方法:确认它是否正确设置了ContentLength。如果该方法已经根据请求体计算并设置了长度,手动赋值会导致冲突;如果没处理,可在获取请求流前,根据请求体的UTF8字节数设置:
byte[] bodyBytes = Encoding.UTF8.GetBytes(requestBody); request.ContentLength = bodyBytes.Length;
注意必须在GetRequestStream()之前设置ContentLength。
- 禁止重复设置
ContentLength:如果ConstructWebRequest已经帮你处理了这个值,直接去掉手动设置的代码,避免数值冲突。
为什么打印ContentLength是857还报错?
request.ContentLength只是一个属性值,实际写入流的字节数可能因为流未关闭/刷新,导致服务器没收到完整的857字节,或者流内部计数和该属性不一致。关闭流会强制发送缓冲区字节,同时让HttpWebRequest确认写入字节数和ContentLength匹配。
内容的提问来源于stack exchange,提问作者Phil
相关产品推荐
相关产品推荐

