【问题标题】:Response from httpHandler is randomly missing characters on client来自 httpHandler 的响应在客户端随机丢失字符
【发布时间】:2019-09-12 00:56:55
【问题描述】:

问题:

当浏览器接收到来自我们 .NET 站点的响应时,通常会随机丢失原始的部分内容(以两个字符块的形式)

详情:

我们有一个名为 CssCombineHandler 的自定义 httpHandler,它将多个 CSS 文件的内容合并到一个 axd 文件中。

在 web.config 中是这样指定的:

<httpHandlers>
  <add path="css.axd" verb="*" type="MyNamespace.CssCombineHandler, MyNamespace"/>
</httpHandlers>

通过这样的 URL 调用...

http://example.com/css.axd?files=..%2fcss%2fFile1.css%2c..%2fcss%2fFile2.css%2c..%2fcss%2fFile3.css

files 参数中列出的所有文件都会合并到响应中。

相关代码是这样的:

    context.Response.ClearHeaders()
    context.Response.ContentType = "text/css"        
    context.Response.Cache.SetExpires(someDate)
    context.Response.Cache.SetMaxAge(someOtherDate)
    context.Response.Cache.SetCacheability(HttpCacheability.Public)
    context.Response.Cache.VaryByParams("files") = True    
    context.Response.BufferOutput = False  'See notes about this below

    Dim responseBody As New StringBuilder()

    '(Loop through files here)
    responseBody.Append(File.ReadAllText(context.Server.MapPath(currentFileUri.AbsolutePath)))
    '(end loop)

    context.Response.Write(responseBody.ToString())  'Here it has the full, correct string!

但是当您检查响应时(例如,在 Firefox 或 Chrome 开发工具的“网络”选项卡中),它通常至少有一个地方连续两个字符被删除。效果是随机的,取决于它发生的位置,但例如,原始中的这个 CSS...

visibility:visible!important;

...可能会变成...

visibilitvisible!important;

我已经在组合文件中看到这种情况发生了 0-3 次,这在某种程度上取决于其总大小。对合并文件内容的任何更改(即更改正在合并的文件之一,或更改正在合并的文件列表)都可能导致丢失的字符移动到不同的位置。

我尝试过的事情:

我没有用过这么多的东西,所以请原谅我的无知。这是我迄今为止尝试过的。

  • 设置Response.BufferOutput = True。这似乎首先解决了它。我可以看到响应现在有一个自动生成的 content-length 标头,并且不再有 Transfer-Encoding: chunked 标头。

这适用于小响应但是如果我有多个文件被组合,就像响应太大并且某些东西(.NET?IIS?)迫使它回到分块模式,然后再次缺少字符。我不知道阈值,但例如 15k 响应会正确缓冲,但 82k 响应不会

  • 我认为可能是编码问题,因为有些 css 文件是 UTF-8,有些是 Windows-1252。我手动将它们全部更改为 UTF-8,添加
 context.Response.ContentEncoding = Encoding.UTF8
 context.Response.Charset = "UTF-8"

改成

File.ReadAllText(context.Server.MapPath(currentFileUri.AbsolutePath), Encoding.UTF8)

...但这并没有什么不同。这实际上是有道理的,因为我认为 Response.Write() 中的字符串已经是正确的,所以组合不同的文件似乎不是问题。

  • 通过在 IIS 中禁用静态和动态压缩,确认 gzip 不是问题

  • 尝试在 IIS 中将 ASP Response Buffering Limit 设置为 2147483647

  • 尝试手动设置 Content-Length 标头以查看它是否会覆盖自动分块(根据我阅读的某些内容 like this)。我不知道如何获得合适的大小,但即使像这样进行测试,响应中也不会显示 Content-Length 标头。

context.Response.AddHeader("Content-Length", "500000")
  • 尝试使用OutputStream 而不是Response.Write()
Dim bytes As Byte() = System.Text.Encoding.UTF8.GetBytes(responseBody.ToString())
context.Response.OutputStream.Write(bytes, 0, bytes.Length)

注意事项:

  • ASP.NET 4.0,Web 窗体应用程序
  • IIS 10,应用程序池以经典模式运行
  • 此处理程序不调用Response.Flush()
  • 此处理程序未触及Response.Filter
  • 虽然我将问题描述为随机问题,但它仍然足够一致,不会是奇怪的网络故障或其他问题。我可以在本地复制它,也可以在我们的 beta 和 prod 服务器上复制它。对于同一时间的同一组合文件,我可以始终如一地在客户端上重现给定的响应。

【问题讨论】:

    标签: asp.net iis httpresponse httphandler


    【解决方案1】:

    事实证明,我们有一个单独的 http 模块,我们在其中设置了一个 Response.Filter 以将 CSS 文件中的 URL 动态替换为环境的正确值(例如 beta 与生产 URL)。

    显然,当您使用过滤器时,它会使用内部流或其他东西,我仍然不确定确切原因,但是将各种流(当总内容对于一个流来说太大时?)组合成问题响应的最终输出。

    我们通过避免在合并的 css.axd 文件上运行此过滤器并仅在普通 css 文件上执行此过滤器来修复它(以防任何直接命中)。然后在我们的 cssCombineHandler 中,我们在 response.write() 之前的组合 CSS 字符串上运行相同的替换逻辑。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-27
      • 2016-03-25
      • 2018-05-09
      • 2012-12-16
      相关资源
      最近更新 更多