【发布时间】: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