【问题标题】:.Net Core MVC - cannot get 406 - Not Acceptable, always returns 200 OK with Json.Net Core MVC - 无法获得 406 - 不可接受,始终使用 Json 返回 200 OK
【发布时间】:2018-11-20 10:47:15
【问题描述】:

我希望我的应用程序尊重浏览器接受标头并返回 406,如果它与响应格式不匹配。

我在 Mvc 配置中设置了这个选项:

    /// <summary>
    /// This method gets called by the runtime. Use this method to add services to the container.
    /// </summary>
    /// <param name="services">The collection of the services.</param>
    /// <returns>The provider of the service.</returns>
    public IServiceProvider ConfigureServices(IServiceCollection services)
    {
        // add mvc services
        services.AddMvc(options =>
                {
                    options.RespectBrowserAcceptHeader = true;
                    options.ReturnHttpNotAcceptable = true;

                    options.CacheProfiles.Add(
                        "CodebookCacheProfile",
                        new CacheProfile()
                        {
                            Duration = (int)TimeSpan.FromDays(1).TotalSeconds
                        });
                })
                .AddControllersAsServices()
                .AddJsonOptions(options =>
                {
                    options.SerializerSettings.Converters.Add(new StringEmptyToNullConverter());
                    options.SerializerSettings.Converters.Add(new StringEnumConverter(true));
                });

        // add response compression services
        services.AddResponseCompression(options =>
        {
            options.EnableForHttps = true;
            options.Providers.Add<GzipCompressionProvider>();
        });

        // add application services
        services.AddSwaggerDoc()
                .AddConfiguration(configuration)
                .AddModel()
                .AddDataAccess(configuration)
                .AddAuthentication(configuration)
                .AddDomainServices()
                .AddSchedulerContainer(() => serviceProvider);

        // initialize container
        serviceProvider = services.CreateServiceProvider();

        return serviceProvider;
    }

当我尝试发送这样的请求时:(在任何内容上设置 Accept 标头,例如“text/xml”)

我总是得到 200 OK - 使用“application/json”

我的 CountriesController 看起来像这样:

/// <summary>
/// REST API controller for actions with countries.
/// </summary>    
[AllowAnonymous]
[Area(Area.Common)]
[Route("[area]/Codebooks/[controller]")]
[ResponseCache(CacheProfileName = "CodebookCacheProfile")]
public class CountriesController : ApiController
{
    private readonly ICountryService countryService;

    /// <summary>
    /// Initializes a new instance of the <see cref="CountriesController" /> class.
    /// </summary>
    /// <param name="countryService">The country service.</param>
    public CountriesController(ICountryService countryService)
    {
        this.countryService = countryService ?? throw new ArgumentNullException(nameof(countryService));
    }

    /// <summary>
    /// Gets countries by search settings.
    /// </summary>
    /// <response code="200">The countries was returned correctly.</response>
    /// <response code="401">The unauthorized access.</response>
    /// <response code="406">The not acceptable format.</response>
    /// <response code="500">The unexpected error.</response>
    /// <param name="countrySearchSettings">The search settings of the country.</param>
    /// <returns>Data page of countries.</returns>        
    [HttpGet]
    [ProducesResponseType(typeof(IDataPage<Country>), StatusCodes.Status200OK)]
    [ProducesResponseType(typeof(void), StatusCodes.Status401Unauthorized)]
    [ProducesResponseType(typeof(void), StatusCodes.Status406NotAcceptable)]
    [ProducesResponseType(typeof(ApiErrorSummary), StatusCodes.Status500InternalServerError)]
    [SwaggerOperation("SearchCountries")]
    public IDataPage<Country> Get([FromQuery(Name = "")] CountrySearchSettings countrySearchSettings)
    {
        return countryService.Search(countrySearchSettings);
    }

    /// <summary>
    /// Gets a country.
    /// </summary>
    /// <response code="200">The country was returned correctly.</response>
    /// <response code="400">The country code is not valid.</response>
    /// <response code="401">The unauthorized access.</response>
    /// <response code="406">The not acceptable format.</response>
    /// <response code="500">The unexpected error.</response>
    /// <param name="countryCode">The code of the country.</param>
    /// <returns>Action result.</returns>   
    [HttpGet("{countryCode}")]
    [ProducesResponseType(typeof(Country), StatusCodes.Status200OK)]
    [ProducesResponseType(typeof(ApiValidationErrorSummary), StatusCodes.Status400BadRequest)]
    [ProducesResponseType(typeof(void), StatusCodes.Status401Unauthorized)]
    [ProducesResponseType(typeof(void), StatusCodes.Status406NotAcceptable)]
    [ProducesResponseType(typeof(ApiErrorSummary), StatusCodes.Status500InternalServerError)]
    [SwaggerOperation("GetCountry")]
    public IActionResult Get(string countryCode)
    {
        var country = countryService.GetByCode(countryCode);
        return Ok(country);
    }
}

你知道为什么请求 Accept 标头总是被忽略并且响应总是 200 OK 并且 Json 数据正确吗? 我错过了什么?我认为 RespectBrowserAcceptHeaderReturnHttpNotAcceptable 的设置可以做到这一点......但显然不是。 为什么总是回退到默认的 Json 格式化程序?

【问题讨论】:

  • ICountryService.Search 返回什么?
  • IDataPage&lt;Country&gt; 这基本上是自定义集合...类似于分页列表 - 它包含 IEnumerable&lt;Country&gt; 和其他属性,如 Count、TotalPages、PageNumber、PageSize 等
  • 实际生成 406 结果的代码在哪里?当您始终归还收藏品时,您将始终获得 200。
  • 所以我必须手动检查接受标头中的内容并返回 406?或者如何生成406?我认为当响应格式与接受标头中的内容不同时,它会自动返回
  • 我的假设基于 Content Negotiation Processhere 中所述的内容

标签: c# json model-view-controller asp.net-core http-status-code-406


【解决方案1】:

要使ReturnHttpNotAcceptable 工作,操作返回的类型必须是ObjectResult(例如Ok(retval))或未实现IActionResult 的类型(在这种情况下,MVC 框架会将其包装在ObjectResult 给你)。

这是因为 MVC 框架仅在 ObjectResultExecutor 中检查 ReturnHttpNotAcceptable 的值,而不在任何其他 IActionResultExecutor 实现(如 ViewResultExecutor)中检查。 (参见ObjectResultExecutorViewResultExecutor的源代码)

简单地说,确保您返回的类型没有实现(或继承自任何实现的)IActionResult。

【讨论】:

  • 即使我也遇到了同样的问题,返回类型是 IActionResult 但操作总是返回 JsonResult 的实例。在我更改为返回 objectresult 的实例之后。成功了。!!
【解决方案2】:

在 Startup.cs 的 ConfigureServices 方法中添加以下行

services.AddMvcCore().AddJsonFormatters().AddApiExplorer();

【讨论】:

  • 这是做什么的,为什么它会帮助 OP?
猜你喜欢
  • 2019-03-15
  • 2013-04-26
  • 1970-01-01
  • 1970-01-01
  • 2015-07-10
  • 1970-01-01
  • 2011-11-19
相关资源
最近更新 更多