尝试反序列化从 jQuery.ajax() 发送的 JSON 数据时,我的 (C#) 服务器代码中偶尔会出现异常。POST 数据完全是 NULL 字符(二进制,0x00)。我在我的日志和文本模式中记录了所有来自错误的 POST 数据,它看起来像空格:
" "
但在二进制模式下,它是:
00 00 00 00 00 00 00 00 00 00
这个完全相同的错误已经记录了 3 次,来自同一个用户,相隔大约 15 分钟。
会发生什么?我用谷歌搜索并没有找到这样的东西。
这是来自 JSON 反序列化器的实际错误:
System.ArgumentException: Invalid JSON primitive: .
at System.Web.Script.Serialization.JavaScriptObjectDeserializer.DeserializePrimitiveObject()
at System.Web.Script.Serialization.JavaScriptObjectDeserializer.DeserializeInternal(Int32 depth)
at System.Web.Script.Serialization.JavaScriptObjectDeserializer.BasicDeserialize(String input, Int32 depthLimit, JavaScriptSerializer serializer)
at System.Web.Script.Serialization.JavaScriptSerializer.Deserialize[T](String input)
用户代理:
Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.04506.648; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; MS-RTC LM 8; InfoPath.2)
内容类型:
application/json
另一个线索:在我们的全局错误处理程序中,我们尝试向用户写入响应消息(例如“抱歉,您遇到了问题,我们正在调查。”)。当我们尝试为该用户执行此操作时,每次都会遇到相同的异常:
System.Web.HttpException (0x80070057): The remote host closed the connection. The error code is 0x80070057.
at System.Web.Hosting.IIS7WorkerRequest.RaiseCommunicationError(Int32 result, Boolean throwOnDisconnect)
at System.Web.Hosting.IIS7WorkerRequest.ExplicitFlush()
at System.Web.HttpResponse.Flush(Boolean finalFlush)
at System.Web.HttpResponse.End()
以下是我们读取数据的方式(我不得不复制/粘贴我们的一些库代码):
[Ajax]
[AsyncTimeout(300001)] // 5 minutes
[ValidateInput(false)] // We want to pass in XML via POST
public void CommandAsync()
{
AsyncManager.OutstandingOperations.Increment();
// Reads the main body of a request, without closing the
// stream. The advantage of not closing the stream is that it can
// be re-read later, particularly by the Global.asax.cs error
// handler.
// It seems that if the content type is not form-url-encoded
// then the input stream needs to be reset. Weird.
Request.InputStream.Position = 0;
byte[] content = new byte[Request.ContentLength];
Request.InputStream.Read(content, 0, Request.ContentLength);
string dataStr = Encoding.UTF8.GetString(content);
if (dataStr.Length != 0) {
var data = serializer.Deserialize<Dictionary<string, object>>(dataStr);
// do something with data
}
}
[编辑]
Eric 说得对,IE 没有在流中发送数据。
所以我们的解决方案是将数组缩小到读取的内容:
int content_length = request.ContentLength;
byte[] content = new byte[content_length];
int read = request.InputStream.Read(content, 0, content_length);
if (read < content_length)
Array.Resize(ref content, read);
或者,我们可以简单地使用 StreamReader(request.InputStream).ReadToEnd() ,它的效率会低一些,但永远不会有这个错误。