【问题标题】:ServiceStack - Using gzip/deflate compression with JSONP requestsServiceStack - 对 JSONP 请求使用 gzip/deflate 压缩
【发布时间】:2013-11-11 01:02:56
【问题描述】:

我有一个使用 RequestContext.ToOptimizedResult() 压缩响应的 ServiceStack 服务,例如:

[Route("/numbers/search")]
public class FindNumbers
{
}

public object Get(FindNumbers query)
{
    var data = new List<string> { "One", "Two", "Three" };
    return RequestContext.ToOptimizedResult(data);
}

这在发出如下请求时非常有效:

GET http://myhost:13487/numbers/search.json

并按预期使用Accept-Encoding 请求标头进行压缩:

Accept-Encoding: gzip,deflate,sdch

我也可以发出 JSONP 请求:

GET http://myhost:13487/numbers/search?callback=func

正确返回application/javascript 回调(未压缩)。

问题

当我将 Accept-Encoding 请求标头添加到 JSONP 请求时,响应是按照原始 JSON 请求压缩的 JSON 数据,而不是压缩的 application/javascript 回调。

是否有任何明显的原因让我错过了这种行为,或者它只是 ServiceStack 中的一个错误?我的期望是在响应中收到一个压缩的 JSONP 回调,但我对 JSONP 相当熟悉,并且可能有充分的理由进行回退。

请注意,我正在研究 ServiceStack 源代码,但我想我会得到这个,因为更多的大脑比一个更好......

提前致谢

编辑

所以,我已经将问题追溯到以下来源

https://github.com/ServiceStack/ServiceStack/blob/5d09d439cd1a13712411552e2b3ede5a71af2ee5/src/ServiceStack/Host/Handlers/GenericHandler.cs#L79

https://github.com/ServiceStack/ServiceStack/blob/5d09d439cd1a13712411552e2b3ede5a71af2ee5/src/ServiceStack/Host/RestHandler.cs#L107

if (doJsonp && !(response is CompressedResult))
    return httpRes.WriteToResponse(httpReq, response, (callback + "(").ToUtf8Bytes(),")".ToUtf8Bytes());

return httpRes.WriteToResponse(httpReq, response);

因此,如果响应是压缩结果,那么无论通过?callback=func 对 JSONP 的要求如何,响应都将仅包含压缩的 json(在上面的示例中),这与我上面的发现相符。所以看起来需要在调用堆栈中更早地应用 jsonp 回调包装器。

【问题讨论】:

    标签: c# jsonp gzip servicestack deflate


    【解决方案1】:

    对于那些感兴趣的人,我通过编写一个压缩插件来解决这个问题,该插件拦截响应并处理服务方法的外部压缩,这是我认为应该完成的地方。它还解决了上述 JSONP 问题。

    在我看来,压缩是服务方法逻辑的一个正交问题,将其作为响应过滤器移到服务方法之外,可以使服务到服务调用以固有的强类型存在,而不是丑陋的public object MyServiceMethod(DtoType request) { } 签名允许任意压缩/未压缩响应。我在这里假设如果客户端声明了一个有效的Accept-Encoding 标头,那么无论如何都会压缩响应,我认为这是一个公平的要求。

    目前,我选择反对对 ServiceStack 的拉取请求,因为我认为这是框架处理压缩方式的重大变化,并且需要与所有者进行大量的前期讨论。此代码纯粹用于演示目的,但我正在使用它并且效果很好。

    代码:

    public class CompressionFeature : IPlugin
    {
        public void Register(IAppHost appHost)
        {
            appHost.ResponseFilters.Add((request, response, dto) =>
            {
                if (dto == null || dto is AuthResponse || dto is CompressedResult || dto is Exception) return;
    
                using (var serializationContext = new HttpRequestContext(request, response, dto))
                {
                    if (!serializationContext.RequestAttributes.AcceptsDeflate && !serializationContext.RequestAttributes.AcceptsGzip) return;
    
                    var serializedDto = EndpointHost.ContentTypeFilter.SerializeToString(serializationContext, dto);
    
                    var callback = request.GetJsonpCallback();
                    var isJsonpRequest = EndpointHost.Config.AllowJsonpRequests && !string.IsNullOrEmpty(callback);
    
                    if (isJsonpRequest)
                    {
                        serializedDto = (callback + "(") + serializedDto + ")";
                        serializationContext.ResponseContentType = ContentType.JavaScript;
                    }
    
                    var compressedBytes = serializedDto.Compress(serializationContext.CompressionType);
                    var compressedResult = new CompressedResult(compressedBytes, serializationContext.CompressionType, serializationContext.ResponseContentType);
                    response.WriteToResponse(compressedResult, serializationContext.ResponseContentType);
                }
            });
        }
    }
    

    在您的 AppHost 中注册插件:

    appHost.Plugins.Add(new CompressionFeature());
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-05-05
      • 1970-01-01
      • 2011-06-11
      • 2011-01-22
      • 1970-01-01
      • 2015-07-21
      相关资源
      最近更新 更多