我有一个使用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源进行工作,但我认为我会在那里得到这个,因为更多的大脑比一个更好......
提前致谢
修改
所以,我已经将这个问题追溯到以下来源
和
if (doJsonp && !(response is CompressedResult))
return httpRes.WriteToResponse(httpReq, response, (callback + "(").ToUtf8Bytes(),")".ToUtf8Bytes());
return httpRes.WriteToResponse(httpReq, response);
因此,如果响应是压缩结果,那么无论通过?callback=func
对JSONP的要求如何,响应将只包含压缩的json(在上面的示例中),这与我上面的发现完全一致。所以看起来需要在callstack中更早地应用jsonp回调包装器。
答案 0 :(得分:9)
对于那些感兴趣的人,我通过编写一个压缩插件来解决这个问题,该插件拦截响应并处理服务方法的压缩外部,这是我认为应该完成的。它还解决了上述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());