为什么每个 IIS 响应的末尾(作为最后一个字节)可能有一个 UTF-8 BOM?
Why might there be a UTF-8 BOM at the end (as the last bytes) of each IIS response?
在通过 IIS 管道运行并发出带有字符集的内容类型(根据 <globalization>
元素)的每个页面的末尾,UTF-8 BOM 被 添加到响应结束。这是无效的并且破坏了 UpdatePanel 的使用。
如果添加了BOM,应该是第一个字符..
curl | xxd
将最后三个字节显示为 EF BB BF
,或 UTF-8 BOM。
0002b830: 2f62 6f64 793e 0d0a 3c2f 6874 6d6c 3eef /body>..</html>.
0002b840: bbbf ..
备注:
这个问题不会困扰通过静态文件处理程序的响应。这表明问题出在托管/ASP.NET 管道中。
如果在写入一些虚拟数据后立即调用 Request.End()
,仍然会出现此问题。这应该意味着问题不是由任何进一步的请求处理程序或软包装程序引起的,因为它会导致 ThreadAbortException 传播。
MVC 和 ASP.NET WebForm 页面受到同样的影响。
ASHX 请求不受影响。
当更改为使用 <globalization responseEncoding="utf-8" ..>
.
时,问题开始出现,或者至少变得非常明显
这样的 BOM/字符确实不会出现在请求中使用的源文件的末尾,更不用说每个受影响的文件了。 (代码库没有 non-starting/BOM 次 \xEF\xBB\xBF
,也没有任何 \xFE\xFF
或 \xFF\xFE
。)
所有未随 IIS 或 ASP.NET MVC 一起提供的 IIS 模块已被删除,问题仍然存在。
可能是什么问题,故障排除的后续步骤是什么?
这个问题完全是 ASP.NET 管道相关的,因为一些很棒的“处理程序”被添加到 MVC 管道(通过 Global.asax 中注册的过滤器)和 WebForms(通过添加一个基页..);两种形式最终都将 HttpContext.Response.Filter
重新分配给了一个特殊的代表 .. 或者在这种情况下,多个包装的代表。
这些“处理程序”有效地导致写入一个流的内容,然后是来自另一个“处理程序”的 empty-except-for-BOM 响应,效果类似于:
_stream.Write(someOutputBuffer, ..);
_stream.Write(originalBuffer, ..);
因此,如果 originalBuffer
碰巧是空的,除 BOM 外,输出将在“末尾”附加 BOM,而不是中间某处的同样无效的位置响应..
切换到 UTF-8 响应编码导致了该行为,因为这些“处理程序”中的每一个都使用当前响应编码打开了一个流,该编码已切换到 UTF-8,并且默认的 UTF-8 编码将发出默认为 BOM。
修复是 create the UTF-8 encoding used in a way that specifies not to emit the BOM by default,而不是直接使用 Response.ContentEncoding
(带 BOM 的 UTF-8)。 (代码完全可疑,尽管那是另一天的任务..)
tldr; 简陋的“处理程序”并不总是安装为 IIS modules/handlers。
在通过 IIS 管道运行并发出带有字符集的内容类型(根据 <globalization>
元素)的每个页面的末尾,UTF-8 BOM 被 添加到响应结束。这是无效的并且破坏了 UpdatePanel 的使用。
如果添加了BOM,应该是第一个字符..
curl | xxd
将最后三个字节显示为 EF BB BF
,或 UTF-8 BOM。
0002b830: 2f62 6f64 793e 0d0a 3c2f 6874 6d6c 3eef /body>..</html>.
0002b840: bbbf ..
备注:
这个问题不会困扰通过静态文件处理程序的响应。这表明问题出在托管/ASP.NET 管道中。
如果在写入一些虚拟数据后立即调用
Request.End()
,仍然会出现此问题。这应该意味着问题不是由任何进一步的请求处理程序或软包装程序引起的,因为它会导致 ThreadAbortException 传播。MVC 和 ASP.NET WebForm 页面受到同样的影响。
ASHX 请求不受影响。
当更改为使用
时,问题开始出现,或者至少变得非常明显<globalization responseEncoding="utf-8" ..>
.这样的 BOM/字符确实不会出现在请求中使用的源文件的末尾,更不用说每个受影响的文件了。 (代码库没有 non-starting/BOM 次
\xEF\xBB\xBF
,也没有任何\xFE\xFF
或\xFF\xFE
。)
所有未随 IIS 或 ASP.NET MVC 一起提供的 IIS 模块已被删除,问题仍然存在。
可能是什么问题,故障排除的后续步骤是什么?
这个问题完全是 ASP.NET 管道相关的,因为一些很棒的“处理程序”被添加到 MVC 管道(通过 Global.asax 中注册的过滤器)和 WebForms(通过添加一个基页..);两种形式最终都将 HttpContext.Response.Filter
重新分配给了一个特殊的代表 .. 或者在这种情况下,多个包装的代表。
这些“处理程序”有效地导致写入一个流的内容,然后是来自另一个“处理程序”的 empty-except-for-BOM 响应,效果类似于:
_stream.Write(someOutputBuffer, ..);
_stream.Write(originalBuffer, ..);
因此,如果 originalBuffer
碰巧是空的,除 BOM 外,输出将在“末尾”附加 BOM,而不是中间某处的同样无效的位置响应..
切换到 UTF-8 响应编码导致了该行为,因为这些“处理程序”中的每一个都使用当前响应编码打开了一个流,该编码已切换到 UTF-8,并且默认的 UTF-8 编码将发出默认为 BOM。
修复是 create the UTF-8 encoding used in a way that specifies not to emit the BOM by default,而不是直接使用 Response.ContentEncoding
(带 BOM 的 UTF-8)。 (代码完全可疑,尽管那是另一天的任务..)
tldr; 简陋的“处理程序”并不总是安装为 IIS modules/handlers。