【发布时间】: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 数据正确吗? 我错过了什么?我认为 RespectBrowserAcceptHeader 和 ReturnHttpNotAcceptable 的设置可以做到这一点......但显然不是。 为什么总是回退到默认的 Json 格式化程序?
【问题讨论】:
-
ICountryService.Search返回什么? -
IDataPage<Country>这基本上是自定义集合...类似于分页列表 - 它包含IEnumerable<Country>和其他属性,如 Count、TotalPages、PageNumber、PageSize 等 -
实际生成 406 结果的代码在哪里?当您始终归还收藏品时,您将始终获得 200。
-
所以我必须手动检查接受标头中的内容并返回 406?或者如何生成406?我认为当响应格式与接受标头中的内容不同时,它会自动返回
-
我的假设基于 Content Negotiation Process 下here 中所述的内容
标签: c# json model-view-controller asp.net-core http-status-code-406