2014-03-04 55 views
7

我有一个使用WebForms的ASP.NET 3.5应用程序,目前它正在IIS6上承载。一切都很好。ASP.NET在切换到IIS8后连接断开时处理请求

但是,在切换到安装了IIS8的Windows 2012服务器后,我们会间歇性地收到截断的请求。大多数情况下,这会在我们的事件日志中显示一个视图状态异常,但是,在没有ViewState的表单上,我们会收到不完整的帖子(最后几个字段丢失/部分截断)。

这成为那么多问题,我们升级到微软的支持,和调试星期后,他们说这是II7和上面的“正确”的行为。他们的解释是,从6 IIS管道7

IIS6的变化,下面将其传递到Asp.net之前将缓冲整个请求,截断请求将被忽略。
IIS7及以上版本会在发送初始头文件后将请求发送到Asp.net,这将由应用程序处理截断的请求。

时要么有连接问题(用户tranmission期间拔掉他们的有线电视)或一个职位期间,当用户按下停止/重新加载页面后,此成为问题。

在我们的HTTP日志中,我们看到与截断的请求相关的“connection_dropped”消息。

我无法相信,这种行为是有意的,但我们有一些不同的服务器上进行测试,并得到与IIS7和上面相同的结果(Windows 2008中,2008 R2,和2012年)。

我的问题是:

1)请问这种行为甚至有意义吗? 2)如果这是“正确的”行为,你如何保护你的应用程序免受潜在处理不完整的数据?

3)为什么应用程序开发人员有责任检测不完整的请求?假设,为什么应用程序开发人员会处理不完整的请求,而忽略它?

更新

我写了一个小型的asp.net应用程序和网站来演示这个问题。

服务器

Handler.ashx.cs

public class Handler : IHttpHandler 
{ 
    public void ProcessRequest(HttpContext context) 
    { 
     if (context.Request.HttpMethod == "POST") 
     { 
      var lengthString = context.Request.Form["Length"]; 
      var data = context.Request.Form["Data"]; 

      if (lengthString == null) 
      { 
       throw new Exception("Missing field: Length"); 
      } 

      if (data == null) 
      { 
       throw new Exception("Missing field: Data"); 
      } 

      var expectedLength = int.Parse(lengthString); 

      if (data.Length != expectedLength) 
      { 
       throw new Exception(string.Format("Length expected: {0}, actual: {1}, difference: {2}", expectedLength, data.Length, expectedLength - data.Length)); 
      } 
     } 

     context.Response.ContentType = "text/plain"; 
     context.Response.Write("Hello World, Request.HttpMethod=" + context.Request.HttpMethod); 
    } 

    public bool IsReusable 
    { 
     get { return false; } 
    } 
} 

客户

的Program.cs

static void Main(string[] args) 
{ 
    var uri = new Uri("http://localhost/TestSite/Handler.ashx"); 
    var data = new string('a', 1024*1024); // 1mb 

    var payload = Encoding.UTF8.GetBytes(string.Format("Length={0}&Data={1}", data.length, data)); 

    // send request truncated by 256 bytes 
    // my assumption here is that the Handler.ashx should not try and handle such a request 
    Post(uri, payload, 256); 
} 

private static void Post(Uri uri, byte[] payload, int bytesToTruncate) 
{ 
    var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp) 
    { 
     // this allows us to disconnect unexpectedly 
     LingerState = new LingerOption(true, 0) 
    }; 

    socket.Connect(uri.Host, uri.Port); 

    SendRequest(socket, uri, payload, bytesToTruncate); 

    socket.Close(); 
} 

private static void SendRequest(Socket socket, Uri uri, byte[] payload, int bytesToTruncate) 
{ 
    var headers = CreateHeaders(uri, payload.Length); 

    SendHeaders(socket, headers); 

    SendBody(socket, payload, Math.Max(payload.Length - bytesToTruncate, 0)); 
} 

private static string CreateHeaders(Uri uri, int contentLength) 
{ 
    var headers = new StringBuilder(); 

    headers.AppendLine(string.Format("POST {0} HTTP/1.1", uri.PathAndQuery)); 
    headers.AppendLine(string.Format("Host: {0}", uri.Host)); 
    headers.AppendLine("Content-Type: application/x-www-form-urlencoded"); 
    headers.AppendLine("User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:26.0) Gecko/20100101 Firefox/99.0"); 
    headers.AppendLine("Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"); 
    headers.AppendLine("Connection: Close"); 
    headers.AppendLine(string.Format("Content-Length: {0}", contentLength)); 

    return headers.ToString(); 
} 

private static void SendHeaders(Socket socket, string headers) 
{ 
    socket.Send(Encoding.ASCII.GetBytes(headers)); 
    socket.Send(Encoding.ASCII.GetBytes("\n")); 
} 

private static void SendBody(Socket socket, byte[] payload, int numBytesToSend) 
{ 
    socket.Send(payload, 0, numBytesToSend, SocketFlags.None); 
} 

回答

2

1)如果你正在运行的管道的应用程序池到您的3.5应用程序以集成模式分配,您可能在处理请求时遇到问题编号due to ISAPI behavior。您可能会生成不正确理解的请求,然后将它们截断为默认值。您是否尝试过在经典模式下运行应用程序池?

2)功能测试。许多功能测试。创建一个测试工具并进行应用程序可以进行的所有调用,以确保其正常工作。这不是一个100%的解决方案,但没有什么是真的。有很多计算机科学论文解释了为什么不可能测试您的应用可能运行based on the Halting Problem的每种可能情况。

3)因为您编写了代码。你不应该有不完整的请求,因为请求可能是一个重要的数据部分,你需要发回一个错误,说明处理请求时出现问题,否则发布方只会将请求视为神秘消失。

+0

当用户在浏览器上按下停止按钮时,可能会出现此问题。无论我处于集成还是经典模式都无关紧要。至于你的第二点,这看起来像是框架应该保护你的东西,asp.net应该是HTTP之上的抽象。虽然这绝对是一个抽象的漏洞,但我觉得这是我不应该写的一个问题。写这个问题非常困难。我将用测试程序更新原始问题以证明问题。 – Matthew

+0

测试程序可能是最好的。与此同时,是的,我可以理解你对预测这种低杠杆错误感到沮丧,但正如你所说,这是一个漏洞抽象和漏洞抽象只能保护你不受这么多。 FWIW,我从来没有见过这种情况发生在4.0或4.5。 – gfish3000

+0

我更新了原始问题的复制 – Matthew

2

IIS改变它的行为的原因,因为我们(开发人员)需要更多的控制请求处理。如果请求中断,我们在调查无形请求的原因方面存在问题。我们需要在应用程序级别上记录请求&记录保存。例如,如果请求涉及信用卡交易等金融交易,我们需要更多的控制权,并且我们需要记录每个步骤的合规性。

IIS是一个Web服务器框架,应用程序级数据验证不是他们的责任。如果请求被破坏,那意味着输入不完整&应用程序级逻辑将决定要做什么。应用程序必须响应正确的错误代码和失败。这是ASP.NET mvc具有模型验证的原因,它允许您验证应用程序级别的完整输入。

您可以使用IsClientConnected检查底层套接字是否仍连接。

由于网络AJAX更多,移动性更强,而且我们有时使用ping来检查远程服务的运行状况,所以我们不一定认为断开的请求是错误,必须放弃。我们可能仍然希望忍受破碎的请求。这是应用程序级开发人员可以做出的选择,而不是IIS。