How to ensure that ServiceStack always returns JSO

2019-07-16 12:01发布

问题:

We have decided to only allow requests with a Content-Type header "application/json". So, whenever we receive a request with an alternative or missing Content-Type header, we throw an HttpError. This should return a 400 response containing a JSON ResponseStatus body with relevant info. However, if a Content-Type text/plain is sent, we throw an HttpError, but the response's Content-Type is text/plain and content-length: 0. I expected ServiceStack's ResponseStatus to be returned. The ResponseStatus is returned fine if I add an Accept application/json header to the request. I executed the request using Postman. Fiddler4 screen shot:

I am aware that Postman adds the Accept / header. So my question is: How can I ensure that a thrown HttpError always return the ResponseStatus as JSON, no matter the request's Accept header?

The 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
        });

As I understand it, the DefaultContentType is only used whenever there isn't an Accept header in the request.

The 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.");
        });

回答1:

The HTTP Accept header is what the client uses to indicate what Response Type should be returned but you can override this to always return JSON by adding a Global Request Filter and explicitly setting the ResponseContentType, e.g:

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

If the Accept Header doesn't specify a specific Response Type it will default to using the PreferredContentTypes which you can change by:

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