You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何阻止Swashbuckle自动设置Accept请求头?

问题描述

我有一个.NET 7 Web API项目,使用Swashbuckle.AspNetCore生成Swagger UI。其中一个接口会根据响应状态码返回不同的Content-Type:200状态返回application/xml,404状态返回application/json。

我已通过在控制器方法上添加SwaggerResponse特性,让Swagger UI正确展示200的XML示例响应和404的JSON示例响应,这部分正常。

但实际从Swagger UI调用该接口时,即便返回404状态,响应始终是XML格式;而用Postman调用时,404状态会返回JSON。经排查发现:Swagger UI会自动传递Accept: application/xml请求头,触发了内容协商。

Swagger界面中第一个示例旁标注的“Controls Accept header”也印证了这一点。

请问是否可以修改该行为,让Swashbuckle不再自动设置Accept请求头?

复现问题的极简代码示例

Program.cs

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.

builder.Services.AddControllers();

builder.Services
    .AddMvc()
    .AddXmlSerializerFormatters();

// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(c => c.EnableAnnotations());

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();

WeatherForecastController.cs

using System.Runtime.Serialization;
using System.Xml.Linq;
using Microsoft.AspNetCore.Mvc;
using Swashbuckle.AspNetCore.Annotations;

namespace WebApplication1.Controllers
{
    [ApiController]
    [Route("[controller]")]
    public class WeatherForecastController : ControllerBase
    {
        private static readonly string[] Summaries = new[]
        {
            "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
        };

        private readonly ILogger<WeatherForecastController> _logger;

        public WeatherForecastController(ILogger<WeatherForecastController> logger)
        {
            _logger = logger;
        }

        [HttpGet(Name = "GetWeatherForecast")]
        [Produces("application/xml", "application/json")]
        [SwaggerResponse(200, Type = typeof(XDocument), ContentTypes = new[] { "application/xml" })]
        [SwaggerResponse(404, Type = typeof(ProblemDetails), ContentTypes = new[] { "application/json" })]
        public ActionResult<WeatherForecast> Get(string region)
        {
            if (region is not "Yorkshire")
            {
                return this.NotFound();
            }

            var forecast = Enumerable.Range(1, 5).Select(index => new WeatherForecast
            {
                Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
                TemperatureC = Random.Shared.Next(-20, 55),
                Summary = Summaries[Random.Shared.Next(Summaries.Length)]
            })
            .ToArray();

            var doc = new XDocument();
            using (var writer = doc.CreateWriter())
            {
                // write xml into the writer
                var serializer = new DataContractSerializer(forecast.GetType());
                serializer.WriteObject(writer, forecast);
            }

            return this.Content(doc.ToString(), "application/xml");
        }
    }
}

WeatherForecast.cs

namespace WebApplication1
{
    public class WeatherForecast
    {
        public DateOnly Date { get; set; }

        public int TemperatureC { get; set; }

        public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);

        public string? Summary { get; set; }
    }
}
解决方案

有两种可行方式修改Swashbuckle的自动设置Accept头行为:

方法1:全局禁用Swagger UI的Accept头自动设置

在配置SwaggerUI时,通过添加请求拦截器移除自动生成的Accept头:

修改Program.cs中的UseSwaggerUI部分:

app.UseSwaggerUI(c =>
{
    c.RequestInterceptor = "function(request) { delete request.headers['Accept']; return request; }";
});

这段JavaScript会在请求发送前删除Swagger UI自动添加的Accept头,让ASP.NET Core的内容协商逻辑根据接口实际返回的Content-Type响应,不再被强制头干扰。

方法2:针对单个接口调整

如果不想全局修改,可通过自定义IOperationFilter修改目标接口的OpenAPI元数据,移除Swagger UI关联Accept头的标识:

首先创建自定义过滤器:

public class RemoveAcceptHeaderControlFilter : IOperationFilter
{
    public void Apply(OpenApiOperation operation, OperationFilterContext context)
    {
        // 根据Action名称定位目标接口
        if (context.ApiDescription.ActionDescriptor.DisplayName == "WebApplication1.Controllers.WeatherForecastController.Get")
        {
            // 移除控制Accept头的扩展标识
            foreach (var response in operation.Responses.Values)
            {
                foreach (var content in response.Content.Values)
                {
                    content.Extensions.Remove("x-ms-media-type");
                }
            }
        }
    }
}

然后在注册SwaggerGen时添加该过滤器:

builder.Services.AddSwaggerGen(c =>
{
    c.EnableAnnotations();
    c.OperationFilter<RemoveAcceptHeaderControlFilter>();
});

此方式仅对指定接口生效,不影响其他接口的Swagger UI行为。

补充方案(硬编码响应头)

如果只是想确保404返回JSON,也可以在返回NotFound时直接指定响应头:

return NotFound(new ProblemDetails { Title = "Region not found" })
       .WithHeaders(new Dictionary<string, string> { { "Content-Type", "application/json" } });

不过这种方式属于硬编码,不如前两种从Swagger层面解决彻底。


内容的提问来源于stack exchange,提问作者exploring.cheerily.impresses

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 01:46:21