.NET Framework4.8 Swashbuckle Swagger缺Content-Type报错问题
这个报错的核心矛盾有两点,和Swagger文档的consumes配置没有直接关系:
- 按HTTP规范,GET请求默认不携带请求体,你用的Swashbuckle 5.6自带的Swagger UI版本,识别到接口所有参数都来自查询字符串(
in: query)时,判定请求不需要传body,因此不会主动添加Content-Type请求头,也不会显示Content-Type选择下拉框。 - 你的Web API参数绑定逻辑存在默认行为:复杂类型参数
SomeParams默认会尝试通过MediaTypeFormatter从请求体读取数据,哪怕所有参数实际都通过查询字符串传递。当请求没有Content-Type头时,框架会默认将媒体类型推断为application/octet-stream,找不到对应格式化器就直接抛出UnsupportedMediaTypeException。
你之前修改格式化器SupportedMediaTypes配置不生效的原因是:请求缺失Content-Type头时,框架在匹配格式化器之前就已经把媒体类型硬编码为application/octet-stream,根本不会走到你配置的Json格式化器匹配逻辑。自定义Consumes特性不生效的原因是:Swagger UI仅在接口存在in: body类型的参数时,才会读取consumes配置、渲染Content-Type选择器并自动添加对应请求头。
按推荐优先级从高到低选择即可:
方案1:明确标记参数绑定源(最推荐,符合REST规范)
GET请求本身不应该携带请求体,直接给所有GET接口的复杂类型参数加[FromUri]特性,显式告诉Web API从查询字符串绑定参数,框架就不会再尝试读取请求体,从根源上消除对Content-Type头的依赖。
修改控制器方法示例:
[HttpGet] [SwaggerConsumes("application/json")] [SwaggerProduces("application/json")] [Route("api/xxx_V1/GetAll/", Name = "xxx_V1_GetAll")] public Rxxx_V1 GetAll([FromUri]SomeParams xyz) { return AuthorizationController.MainClass.yyy_GetAll_V1(xyz); }
所有接收SomeParams类型的GET方法都加上[FromUri]标记即可,修改后哪怕请求完全不带Content-Type头也能正常响应,同时你现有的Swagger参数打平逻辑不需要调整,测试时参数传递完全正常。
方案2:全局补全默认Content-Type头(无侵入,不需要改业务代码)
如果不想逐个修改控制器方法,可以在Web API管道加一个全局消息处理器,在参数绑定执行前,给缺失Content-Type头的GET请求自动补默认值:
首先在项目中新增处理器类:
public class DefaultContentTypeMessageHandler : DelegatingHandler { protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { if (request.Method == HttpMethod.Get && request.Content != null && request.Content.Headers.ContentType == null) { request.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json"); } return await base.SendAsync(request, cancellationToken); } }
然后在WebApiConfig.cs的路由配置之前注册处理器:
config.MessageHandlers.Add(new DefaultContentTypeMessageHandler());
配置完成后全局生效,所有缺失Content-Type的GET请求都会被自动补头,格式化器可以正常识别Json媒体类型,不会再抛出类型不支持的错误。
方案3:修改Swagger UI配置强制加头(仅解决Swagger测试场景)
如果只需要解决Swagger UI页面测试的报错,不需要兼容其他客户端,可以注入自定义JS给Swagger发出的所有请求强制加Content-Type头。
第一步,在SwaggerConfig.cs的EnableSwaggerUi配置段开启JS注入:
.EnableSwaggerUi(c => { // 替换成你项目的实际命名空间和JS文件路径,文件需设置为嵌入资源 c.InjectJavaScript(Assembly.GetExecutingAssembly(), "YourProjectName.SwaggerCustom.add-content-type.js"); // 保留原有其他配置 });
第二步,新增对应JS文件,写入以下逻辑:
$(function () { swaggerUi.api.clientAuthorizations.add( "global-json-content-type", new SwaggerClient.ApiKeyAuthorization("Content-Type", "application/json", "header") ); });
注意这个方案仅对Swagger UI发起的请求生效,其他客户端调用接口时如果没带Content-Type头依然会报错。
内容的提问来源于stack exchange,提问作者mr R

