【问题标题】:SignalR wth gzip compression带有 gzip 压缩的 SignalR
【发布时间】:2012-09-24 21:20:23
【问题描述】:

在为启用 gzip 压缩的 asp.net 网站中托管的 Hub 开发 SignalR 客户端时遇到一些问题。由于我们使用 IIS 压缩,来自 SignalR 的响应也被压缩,但是,客户端不理解响应,我们在客户端收到 Json 解析错误。

SignalR 内部使用HttpWebRequest 发出http 请求,HttpWebRequest 可以配置为使用AutomaticDecompression 属性自动解压缩响应。所以,如果我能以某种方式获得 SignalR 用来发出请求的HttpWebRequest 对象,我应该能够设置启用自动解压。

我认为我应该能够通过向HubConnection.Start 提供IHttpClient 的自定义实现来访问HttpWebRequestIHttpClient.GetAsync 采取prepareRequest 操作,我认为这应该可以让我访问@ 987654330@,但是,HttpHelper.GetAsync 在传递给prepareRequest 之前将HttpWebRequestHttpWebRequestWrapper 包装在一起,而HttpWebRequestWrapper 不提供对HttpWebRequest 的访问。

HttpHelper 类是内部的,所以也不能使用它,所以,我不确定如何使用 SignalR 启用自动解压缩。

我可以在HttpWebRequestWrapper 中公开HttpWebRequest,但是,如果存在更简单的解决方案,我会更喜欢。有什么想法吗?

我正在使用 SignalR 版本 0.5.1.10822

我的自动解压HttpClient:

public class HttpClientWithAutoDecompression : IHttpClient
{
    readonly DefaultHttpClient _httpClient = new DefaultHttpClient();

    private readonly DecompressionMethods _decompressionMethods;
    public HttpClientWithAutoDecompression(DecompressionMethods decompressionMethods)
    {
        _decompressionMethods = decompressionMethods;
    }

    public Task<IResponse> GetAsync(string url, Action<IRequest> prepareRequest)
    {
        Task<IResponse> task = _httpClient.GetAsync(url, 
            request =>
                {
                    [ERROR: request is actually HttpRequestWrapper and
                     does not expose HttpWebRequest]**              ] 
                    var httpWebRequest = (HttpWebRequest) request; 
                    httpWebRequest.AutomaticDecompression = _decompressionMethods;
                    prepareRequest(request);
                });

        return task.ContinueWith(response =>
        {
            Log.Debug(this, "Response: {0}", response.Result.ReadAsString());
            return response.Result;
        });

    }
....
}

【问题讨论】:

  • 我现在检查了一个也启用了 gzip 压缩的服务器,发现 SignalR.Client 默认不发送 Accept-Encoding: gzip,所以我的服务器响应一个未压缩的消息并且一切都按预期工作。似乎您的客户端错误地发送了 Accept-Encoding 标头,或者您的服务器强制对 gzip 的每个响应(内置 IIS 压缩不会)。你能和 Fiddler 一起看看发生了什么事吗?

标签: signalr


【解决方案1】:

据我所知,GZip 编码和流式传输不会混合使用。在永久帧传输的情况下,客户端将无法解码流内容上的任何内容,直到接收到整个响应或至少一个重要的数据块(由于数据的解码方式)。在 web sockets 的情况下,目前不支持任何类型的编码,尽管对于每个消息编码 being worked on 的规范显然有一个扩展。

也就是说,如果您想尝试为 LongPolling 传输提供支持,我认为这可能的唯一方法是提供您自己的 SignalR IHttpClient 实现。您现在可以看到DefaultHttpClient 类使用HttpHelper::GetAsync 在内部创建HttpWebRequest,但您永远无法得到它,因为此时您只能访问IRequest,即HttpWebRequestWrapper

通过创建您自己的IHttpClient,您可以接管HttpWebRequest 的初始实例化,设置AutomaticDecompression,然后用HttpWebRequestWrapper 自行封装。

【讨论】:

  • 但它应该与 longPolling 传输一起使用,因为在向客户端返回消息时,长时间运行的请求会完成,或者我错过了什么?
  • 谢谢 huys,我明白为什么压缩不适用于流媒体,我认为我的主要问题是 SingnalR Api 接口不允许您访问它用于发出请求的 HttpWebRequest,基本上我想更新httpWebRequest.AutomaticDecompression 属性,但是,SignalR 将“httpWebRequest”包装在不公开 AutomaticDecompression 属性的包装器中。 dfowler 建议我修改包装类并重建 SignalR。现在我只是使用反射来访问我需要访问的私有属性。
  • @akoeplinger 是的,它应该适用于 LP 传输。当然,在使用效率方面,这是最糟糕的传输方式,因此它可能会抵消 gzip 的任何潜在好处,除非您的消息负载碰巧很大。
  • 谢谢 Drew,请注意:您可以创建自己的 IHttpClient,但您也必须实现自己的 HttpHelper::GetAsync,因为 HttpHelper 是内部的,因此您不能在程序集中使用它.因此,我在 DefaultHttpClient 上创建了一个包装器,并使用反射来访问 _request。 FieldInfo requestField = typeof (HttpWebRequestWrapper).GetField("_request", BindingFlags.Instance | BindingFlags.NonPublic); var httpWebRequest = (HttpWebRequest) requestField.GetValue(request); httpWebRequest.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
  • @FaisalMansoor 您不需要 HttpHelper,这实际上只是 SignalR 的内部实现细节。如果您愿意,您可以在 IHttpClient 中直接内联您自己的 HttpWebRequest 实例化。至于反思……没有评论。 :P
猜你喜欢
  • 2015-07-14
  • 2014-05-31
  • 1970-01-01
  • 1970-01-01
  • 2012-01-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多