【问题标题】:ServiceStack client compressionServiceStack 客户端压缩
【发布时间】:2017-01-03 23:36:24
【问题描述】:

我想压缩来自客户端的请求。

我找到了问答: ServiceStack - How To Compress Requests From Client

但是在使用此代码时,我从服务器收到一个 SerializationException,内容应该以“{”而不是“\u001F...”开头

这个解决方案仍然有效还是有其他方法可以压缩客户端请求负载?


更新 1:这是 Fiddler 的输出。要求:

POST http://xxxxxx:8104/entries HTTP/1.1
Accept: application/json
User-Agent: ServiceStack .NET Client 4,51
Accept-Encoding: gzip,deflate
Content-Encoding: gzip
Content-Type: application/json
Host: xxxxxx:8104
Content-Length: 187
Expect: 100-continue

[binary data not shown here]

然后回应:

HTTP/1.1 400 Bad Request
Transfer-Encoding: chunked
Content-Type: application/json; charset=utf-8
Server: Microsoft-HTTPAPI/2.0
Date: Tue, 03 Jan 2017 07:22:57 GMT

427
{"ResponseStatus":{"ErrorCode":"SerializationException","Message":"Could not deserialize 'application/json' request using Namespace.NameOfDto'\nError: System.Runtime.Serialization.SerializationException: Type definitions should start with a '{', expecting serialized type 'NameOfDto', got string starting with: \u001F \b\u0000\u0000\u0000\u0000\u0000\u0004\u00005  \n @\u0010  e 1 P W :h\u001D :D M'YЙ \u001D B| F   7 \r\n   at ServiceStack.Text.Common.DeserializeTypeRefJson.StringToType(TypeConfig typeConfig, String strType, EmptyCtorDelegate ctorFn, Dictionary`2 typeAccessorMap)\r\n   at ServiceStack.Text.Common.DeserializeType`1.<>c__DisplayClass1_0.<GetParseMethod>b__1(String value)\r\n   at ServiceStack.Text.JsonSerializer.DeserializeFromString(String value, Type type)\r\n   at ServiceStack.Text.JsonSerializer.DeserializeFromStream(Type type, Stream stream)\r\n   at ServiceStack.Serialization.JsonDataContractSerializer.DeserializeFromStream(Type type, S
27e
tream stream)\r\n   at ServiceStack.Host.Handlers.ServiceStackHandlerBase.CreateContentTypeRequest(IRequest httpReq, Type requestType, String contentType)","StackTrace":"   at ServiceStack.Host.Handlers.ServiceStackHandlerBase.CreateContentTypeRequest(IRequest httpReq, Type requestType, String contentType)\r\n   at ServiceStack.Host.RestHandler.CreateRequest(IRequest httpReq, IRestPath restPath, Dictionary`2 requestParams)\r\n   at ServiceStack.Host.RestHandler.CreateRequest(IRequest httpReq, IRestPath restPath)\r\n   at ServiceStack.Host.RestHandler.ProcessRequestAsync(IRequest httpReq, IResponse httpRes, String operationName)"}}
0

客户:

public class GzipJsonServiceClient : JsonServiceClient
{
    public GzipJsonServiceClient()
    {
        SetRequestFilter();
    }

    public GzipJsonServiceClient(string baseUri)
        : base(baseUri)
    {
        SetRequestFilter();
    }

    public override void SerializeToStream(IRequest requestContext, object request, Stream stream)
    {
        using (var gzipStream = new GZipStream(stream, CompressionMode.Compress))
        {
            base.SerializeToStream(requestContext, request, gzipStream);
            gzipStream.Close();
        }
    }

    private void SetRequestFilter()
    {
        RequestFilter = req =>
        {
            if (req.Method.HasRequestBody())
            {
                req.Headers.Add(HttpRequestHeader.ContentEncoding, CompressionTypes.GZip);
            }
        };
    }
}

请求代码:

var client = new GzipJsonServiceClient(uri) { Timeout = TimeSpan.FromSeconds(10) };
var request = new NameOfDto();
client.Post(request);

服务端来自 Visual Studio 模板,在 Windows 服务中托管 ServiceStack 服务。这很普通,只有一种方法无法实现:

public void Post(NameOfDto request)
{
    var appHost = (AppHost)HostContext.AppHost;
    ...
}

【问题讨论】:

  • 您能否更新您的问题以显示您正在使用的代码以及使用 Fiddler 之类的原始 HTTP 请求/响应标头。

标签: servicestack


【解决方案1】:

ServiceStack HttpListener Server 和this commit 中的所有 C# 服务客户端都添加了对客户端 Gzip + Deflate 压缩的支持。

这使您可以使用新的RequestCompressionType 属性发送客户端请求,例如:

var client = new JsonServiceClient(baseUrl)
{
    RequestCompressionType = CompressionTypes.GZip,
};

var response = client.Post(new NameOfDto { ... });

此功能从 v4.5.5+ 开始可用,现在是 available on MyGet

【讨论】:

  • 有一个问题...在单元测试中,如果您将“public List Dummy { get; set; }”添加到 Hello 类并用字符串填充它,在 Any 方法中在 HelloService 中,它将作为 null 到达。有什么想法吗?
  • @MartinA 请更新这个问题或问一个有足够代码重现的新问题
  • 在此处添加了后续问题:stackoverflow.com/questions/41466387/…
【解决方案2】:

好的,所以我想出了一种方法来解决我的问题,使用 Newtonsoft JSON nuget。虽然我更希望 ServiceStack 有一个“开箱即用”的解决方案,我不必修改 DTO。

我将 IRequiresRequestStream 接口添加到我的 DTO:

[Route("/entries", "POST")]
public class NameOfDto : IRequiresRequestStream
{
    [ApiMember(IsRequired = true)]
    public string OneOfManyProperties { get; set; }

    public Stream RequestStream { get; set; }
}

然后创建新类:

public static class GZipRequestStreamParser
{
    public static T ParseRequestStream<T>(Stream requestStream)
    {
        using (var gzipStream = new GZipStream(requestStream, CompressionMode.Decompress))
        using (var reader = new StreamReader(gzipStream))
        {
            var serializedObject = reader.ReadToEnd();
            var deserializedObject = JsonConvert.DeserializeObject<T>(serializedObject);
            return deserializedObject;
        }
    }
}

终于更新了端点:

public void Post(NameOfDto request)
{
    request = GZipRequestStreamParser.ParseRequestStream<NameOfDto>(request.RequestStream);

    var appHost = (AppHost)HostContext.AppHost;

    // work with request object!
}

【讨论】:

    猜你喜欢
    • 2016-02-05
    • 1970-01-01
    • 1970-01-01
    • 2013-09-21
    • 2016-04-30
    • 1970-01-01
    • 1970-01-01
    • 2014-08-05
    • 2010-10-23
    相关资源
    最近更新 更多