来自 httpHandler 的响应在客户端随机丢失字符
Response from httpHandler is randomly missing characters on client
问题:
当浏览器收到来自我们 .NET 站点的响应时,通常会随机丢失原始部分(在 two-character 块中)
详情:
我们有一个名为 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
header,不再有 Transfer-Encoding: chunked
header.
这适用于较小的响应 但是 如果我合并了多个文件,就好像响应太大并且某些东西(.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 header 以查看它是否可以覆盖自动分块(根据我阅读的某些内容 like this)。我不知道如何获得合适的尺寸,但即使像这样测试,Content-Length header 也根本不会出现在响应中。
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 服务器上复制它。对于同一时刻的同一个组合文件,我可以在客户端始终如一地重现给定的响应。
事实证明,我们有一个单独的 http 模块,我们在其中设置 Response.Filter
以动态替换 CSS 文件中的 URL 为环境的正确值(例如,测试版与生产 URL) .
显然,当您使用过滤器时,它会使用内部流或其他东西,我仍然不确定确切原因,但是组合各种流时出了点问题(当总内容对于一个流来说太大时? ) 到响应的最终输出中。
我们通过避免 运行 在组合的 css.axd 文件上使用此过滤器并仅在普通 css 文件上使用此过滤器来修复它(以防直接被击中)。然后在我们的 cssCombineHandler 中,我们 运行 在 response.write()
.[=12 之前的组合 CSS 字符串上使用相同的替换逻辑=]
问题:
当浏览器收到来自我们 .NET 站点的响应时,通常会随机丢失原始部分(在 two-character 块中)
详情:
我们有一个名为 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
header,不再有Transfer-Encoding: chunked
header.
这适用于较小的响应 但是 如果我合并了多个文件,就好像响应太大并且某些东西(.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 尝试手动设置 Content-Length header 以查看它是否可以覆盖自动分块(根据我阅读的某些内容 like this)。我不知道如何获得合适的尺寸,但即使像这样测试,Content-Length header 也根本不会出现在响应中。
Response Buffering Limit
设置为 2147483647
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 服务器上复制它。对于同一时刻的同一个组合文件,我可以在客户端始终如一地重现给定的响应。
事实证明,我们有一个单独的 http 模块,我们在其中设置 Response.Filter
以动态替换 CSS 文件中的 URL 为环境的正确值(例如,测试版与生产 URL) .
显然,当您使用过滤器时,它会使用内部流或其他东西,我仍然不确定确切原因,但是组合各种流时出了点问题(当总内容对于一个流来说太大时? ) 到响应的最终输出中。
我们通过避免 运行 在组合的 css.axd 文件上使用此过滤器并仅在普通 css 文件上使用此过滤器来修复它(以防直接被击中)。然后在我们的 cssCombineHandler 中,我们 运行 在 response.write()
.[=12 之前的组合 CSS 字符串上使用相同的替换逻辑=]