【问题标题】:How to ensure that ServiceStack always returns JSON?如何确保 ServiceStack 始终返回 JSON?
【发布时间】:2016-04-14 12:09:42
【问题描述】:

我们决定只允许带有 Content-Type 标头“application/json”的请求。 因此,每当我们收到带有替代或缺少 Content-Type 标头的请求时,我们都会抛出 HttpError。这应该返回一个 400 响应,其中包含带有相关信息的 JSON ResponseStatus 正文。 但是,如果发送 Content-Type text/plain,我们会抛出 HttpError,但响应的 Content-Type 是 text/plain 和 content-length: 0。我希望返回 ServiceStack 的 ResponseStatus。如果我将 Accept application/json 标头添加到请求中,则返回 ResponseStatus 正常。 我使用 Postman 执行了请求。 Fiddler4 屏幕截图:

我知道 Postman 添加了 Accept / 标头。所以我的问题是:无论请求的 Accept 标头如何,如何确保抛出的 HttpError 始终将 ResponseStatus 作为 JSON 返回?

SetConfig:

SetConfig(new HostConfig
        {
            EnableFeatures = Feature.All.Remove( Feature.Html | Feature.Csv | Feature.Jsv | Feature.Xml | Feature.Markdown | Feature.Razor | Feature.Soap | Feature.Soap11 | Feature.Soap12 | Feature.PredefinedRoutes),
            DebugMode = false,
            DefaultContentType = MimeTypes.Json
        });

据我了解,DefaultContentType 仅在请求中没有 Accept 标头时使用。

PreRequestFilter:

PreRequestFilters.Add((request, response) =>
        {
            if (request.Verb.Equals("OPTIONS"))
                response.EndRequest();
            if (request.GetHeader("Content-Type") == null || !request.GetHeader("Content-Type").Equals(MimeTypes.Json))
                throw new HttpError((int)HttpStatusCode.BadRequest, "Bad request", "Expected a Content-Type header with an application/json value but found none. See http://docsdomain.com/ for any required headers.");
        });

【问题讨论】:

    标签: json text servicestack http-error


    【解决方案1】:

    HTTP Accept 标头是客户端用来指示应返回的响应类型,但您可以通过添加全局请求过滤器并显式设置 ResponseContentType 来覆盖它以始终返回 JSON,例如:

    GlobalRequestFilters.Add((req,res,dto) => 
        req.ResponseContentType = MimeTypes.Json);
    

    如果 Accept 标头未指定特定的响应类型,它将默认使用 PreferredContentTypes,您可以通过以下方式进行更改:

    SetConfig(new HostConfig {
        PreferredContentTypes = new []{ MimeTypes.Json }.ToList(),
    });
    

    【讨论】:

    • 我们正在使用 JSON Schema 验证任何请求主体,并且鉴于绝大多数最终用户更喜欢 JSON,我们不会费心实现相同类型的验证 XML 主体。我已将request.ResponseContentType = MimeTypes.Json; 添加到我的 GlobalRespnoseFilter。但是,如果我在 PreRequestfilter 中抛出 HttpError,则 GlobalResponseFilter 永远不会被执行。所以我的回复中仍然收到相同的 Content-Length 和 Content-Type。如果我在 PreRequestFilter 中添加“强制”内容类型,我的服务参数的属性为空。
    • 我刚刚重新阅读了您的答案并注意到,您编写了 GlobalRequestFilter :) 但是在将行添加到我的 GlobalRequestFilter 而不是 GlobalResponseFilter 之后,结果是一样的跨度>
    • 编辑:不完全相同:任何具有 Accept 标头值而不是 /(当然还有 application/json)的请求现在都以预期错误响应状态。但是,我们希望我们的最终用户会使用 Postman 来试验我们的 API,并且由于 Postman 的默认 Accept 标头是 /,它还没有 100% 解决。附言: = *
    • @jk1990 仅供参考,我已经更新了我的答案以显示如何更改首选内容类型。
    • 这很好,而且有效:API 现在返回 JSON,无论 Accept 标头如何。但是,如果请求具有 text/plain 内容类型,我仍然会收到 Content-Type text/plain 和 content-length 0 的响应。在这种情况下(可能是非常极端的情况),我想返回一个 JSON 格式的 ResponseStatus。尽管在 GlobalRequestFilter 中将响应内容类型“强制”为 JSON 并删除了 Setconfig 中的 Feature.Xml,但如果我发送一个内容类型为 application/xml 的 POST,则错误 ResponseStatus 正文仍被格式化为 Xml。跨度>
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-09-19
    • 2012-02-26
    • 1970-01-01
    • 2011-04-16
    • 2018-06-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多