【问题标题】:HttpHandler response is never returned永远不会返回 HttpHandler 响应
【发布时间】:2008-11-11 09:29:27
【问题描述】:

我们有一个相当复杂的 httphandler 来处理图像。基本上,它以所请求的任何大小流式传输图像的任何部分。一些客户端使用这个处理程序没有任何问题。但是我们有一个位置给我们带来了问题,现在它也给我的开发环境带来了问题。

发生的情况是客户端从未收到某些请求的任何内容。所以请求 1 和 2 很好,但请求 3 和 4 永远不会结束。

  • 在调试时,我可以看到服务器已准备就绪并已完成请求。
  • 但客户端仍在等待结果(使用 fiddler2 调试显示未收到响应)

我们用来流式传输图像的代码是

        if (!context.Response.IsClientConnected)
        {
            imageStream.Close();
            imageStream.Dispose();
            return;
        }

        context.Response.BufferOutput = true;
        context.Response.ContentType = "image/" + imageformat;

        context.Response.AppendHeader("Content-Length", imageStream.Length.ToString());

        if (imageStream != null && imageStream.Length > 0 && context.Response.IsClientConnected)
            context.Response.BinaryWrite(imageStream.ToArray());

        if (context.Response.IsClientConnected)
            context.Response.Flush();

        imageStream.Close();
        imageStream.Dispose();

imageStream 是一个包含图像内容的 MemoryStream。

在调用 response.Flush() 之后,我们会进行更多清理并将摘要写入事件日志。

我们还在每次请求后调用 GC.Collect(),因为我们在内存中使用的对象变得非常大。我知道这不是一个好习惯,但它会给我们带来麻烦吗?

在 IIS 5 (Win XP) 和 IIS 6 (Win 2003) 都会出现不返回请求的问题,我们使用 .NET framework v2。

【问题讨论】:

    标签: c# asp.net httphandler


    【解决方案1】:

    首先,有更好的方法来处理整个事情的数组(即MemoryStream 可能在这里是不必要的)。

    我会设想一个循环:

    const int BUFFER_SIZE = 4096; // pick your poison
    bute[] buffer = new byte[BUFFER_SIZE];
    int bytesRead;
    
    while((bytesRead = inStream.Read(buffer, 0, BUFFER_SIZE)) > 0)
    {
        outStream.Write(buffer, 0, bytesRead);
    }
    

    您还应该在禁用缓冲的情况下执行此操作 (.Response.BufferOutput = false)。

    问题是,我怀疑你没有写足够的数据/关闭响应(.Response.Close())。

    【讨论】:

    • 这不是解决方案,但仍然有用!
    • 如果你确实有一个 MemoryStream,但是,有一个更简单的方法:MemoryStream.WriteTo(Stream)
    【解决方案2】:

    客户端将限制它同时向任何一台服务器发出的请求数。此外,当从需要会话状态(默认)的资源请求时,其他需要会话状态的资源的请求将被阻塞。

    使用HttpWebResponse 时,您必须释放该对象或其GetResponseStream 方法返回的流以完成连接。

    您的代码非常混乱。您已经打开了缓冲,设置了内容长度并使用了刷新。这会导致一些奇怪的 HTTP 标头。通常使用缓冲时,您会将 Content-Length 标头的设置留给 ASP.NET 来处理。

    当您使用刷新时,ASP.NET 假定您随后可能会发送更多数据。在这种情况下,它将使用分块传输。一旦响应完成,就会为最终块发送最后一组标头,每个块作为其自己的长度标头,内容的总长度是从这些标头中得出的。第一个块应该有 Content-Length 标头,但是您的代码正在添加该标头。

    如果您自己关闭缓冲并将字节泵入输出流那么您应该自己设置 Content-Length 标头,因为有效地关闭缓冲意味着您对发送到的确切内容负责客户。 Marc 的代码是这种泵的一个简单示例,尽管我会使用更大的缓冲区,或者在 MemoryStream 上,WriteTo 方法会更有效。

    【讨论】:

      【解决方案3】:

      垃圾收集应该不是问题。你为什么将BufferOutput 设置为true?鉴于您只想直接写入数据,我认为将其设置为 false 会更合适。

      我建议您降低诊断级别:使用Wireshark 准确查看网络级别发生的情况。 Fiddler 非常适合 HTTP 级别,但有时您需要更多细节。

      【讨论】:

      • 启用缓冲后,服务器完全有可能还没有发送任何东西,尤其是在长度被破坏的情况下。
      • 根据所写的内容,长度应该没问题 - 并且假设客户端仍然连接有一个 Response.Flush() 。不过这很奇怪。
      • 如果 Buffering 已开启,则无需添加 Content-Length 标头,ASP.NET 将为您完成此操作
      【解决方案4】:

      我们还使用 WebRequest 来收集更多信息。那些阻止了连接。在 WebResponses 周围放置 usings 就可以了。

      using (HttpWebResponse test_resp = (HttpWebResponse)test_req.GetResponse())
      {
      }
      

      我不知道那些会阻止其他请求等...

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-11-15
        • 2011-07-25
        • 1970-01-01
        • 2012-10-02
        • 2013-02-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多