我正在尝试扩展我的 REST 服务(使用 WCF/webHttpBinding 构建),以便客户端可以上传压缩数据。我不确定实现此目的的最佳方法是什么,但我认为通过添加一个 HTTP 模块会相当容易,如果传入请求的内容编码设置为 gzip,该模块将解压缩数据。
所以我创建了一个派生自 IHttpModule 的类,实现如下:
private void OnBeginRequest(object sender, EventArgs e)
{
var app = (HttpApplication) sender;
var context = app.Context;
var contentEncoding = context.Request.Headers["Content-Encoding"];
if (contentEncoding == "gzip")
{
// some debug code:
var decompressedStream = new GZipStream(context.Request.InputStream, CompressionMode.Decompress);
var memoryStream = new MemoryStream();
decompressedStream.CopyTo(memoryStream);
memoryStream.Seek(0, SeekOrigin.Begin);
var streamReader = new StreamReader(memoryStream);
string msg = streamReader.ReadToEnd();
context.Request.InputStream.Seek(0, SeekOrigin.Begin);
app.Request.Filter = //new TestFilterStream(app.Request.Filter);
new System.IO.Compression.GZipStream(
app.Request.Filter, CompressionMode.Decompress);
}
}
我看到的问题是 GZipStream 解压缩实际上从未执行过。我已经确认传入的数据实际上是 gzip 压缩的(msg 变量包含正确的数据)。我还尝试在上面创建自己的流类 (TestFilterStream) 并将其分配给 app.Request.Filter 并且我已经确认流类中没有任何成员实际上被 ASP.NET 调用。所以看起来虽然可以指定一个过滤器,但实际上并没有使用该过滤器。
HttpApplication.Request.Filter 真的没有用吗?
最佳答案
我尝试通过两种方式设置请求过滤器:
- 使用 HttpModule
- 将其设置在
Application_BeginRequest()
(Global.asax) 的开头
两者的结果相同(VS2012 web 项目 + IISExpress):
- 如果没有输入数据(GET 请求或类似请求),则不会调用
Filter.Read
- 如果是带有实际数据的 POST,则执行过滤器并且网络服务获取过滤后的数据
- 即使我在设置过滤器之前从 Request.InputStream 中读取,我仍然会从我的服务代码中触发过滤器。
我没有简单的方法来测试 Gzippet 输入,所以我没有尝试实际的过滤器是否有效。但是,我知道它已被触发,因为我在 GZipStream
尝试查找输入时收到错误消息。
也许您有其他 HttpModule 或 Filter 会破坏您的输入或控制流?
This post提出了一种类似于您的方法,但也说明了以下内容,这可能会导致一些副作用(我的测试未使用 WCF):
"It appears that this approach trigger a problem in WCF, as WCF relies on the original Content-Length and not the value obtained after decompressing."
关于c# - 我可以使用 HTTP 模块更改传入 HTTP 请求的内容吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20249997/