C# Web API提交JSON配置字符串报415/400错误该如何解决?
你遇到的两次报错本质都是ASP.NET Core的[FromBody]参数绑定规则和你传参格式不匹配导致的:
- 415错误:默认情况下
[FromBody]只会处理application/json类型的请求,你传text/plain没有对应的输入格式化器处理,就会返回不支持的媒体类型。 - 改传
application/json后的400错误:[FromBody]绑定string类型参数时,要求请求体是被双引号包裹的JSON字符串字面量,而你直接传了裸的JSON配置内容,JSON格式化器无法解析为string类型,就返回400错误。
方案1:最省心,改服务端直接读原始请求体(推荐)
你的需求是直接存储客户端传过来的原始配置字符串,不需要做模型绑定,完全可以跳过[FromBody]的绑定逻辑,直接读取请求体的原始内容:
[HttpPost("{app}/set")] // POST /api/settings/{app}/set public async Task<bool> Set(string app) { _logger.LogInformation($"recieved request on settings/{app}/set, id: {_requestId}"); try { using var reader = new StreamReader(Request.Body, Encoding.UTF8); string content = await reader.ReadToEndAsync(); System.IO.File.WriteAllText(GetAppSettingsPath(app), content, Encoding.UTF8); _logger.LogInformation($"Completed request for requestId: {_requestId}"); return true; } catch (Exception ex) { _logger.LogError(ex, $"Error on requestId, {_requestId}"); return false; } }
改完之后客户端可以直接传原始配置内容,Content-Type设为text/plain即可,不需要做任何转义,不会再有格式错误。
方案2:保留现有接口代码,调整客户端传参
如果你不想改服务端接口,可以把客户端要传的配置字符串整体转义为JSON字符串字面量,Content-Type保持为application/json:
比如你原来要传的配置内容是{"ConnectionString":"xxx"},实际传的时候要发送成"{\"ConnectionString\":\"xxx\"}",也就是给整个字符串外层加双引号,内部的双引号转义。
另外你之前用HttpClient手动加Content-Type的写法不对,Content-Type属于内容头,应该直接在StringContent构造时指定,不需要手动加请求头:
// 正确的HttpClient写法 var httpRequest = new HttpRequestMessage { Method = HttpMethod.Post, RequestUri = new Uri(_baseUri, string.Concat("api/settings/", app, "/set")), // 第三个参数直接指定媒体类型即可 Content = new StringContent(JsonSerializer.Serialize(content), Encoding.UTF8, "application/json") };
这里用JsonSerializer.Serialize(content)就能自动把你的原始配置字符串转成符合要求的JSON字符串字面量。
方案3:添加纯文本格式化器,适配text/plain请求
如果你既想保留[FromBody] string content的接口写法,又不想转义传参,可以在服务端注册MVC的时候添加官方自带的纯文本输入格式化器:
// Program.cs中注册控制器的部分修改为 builder.Services.AddControllers(options => { options.InputFormatters.Add(new Microsoft.AspNetCore.Mvc.Formatters.StringInputFormatter()); });
注册完成后客户端就可以直接传Content-Type: text/plain的原始配置内容,不需要转义,接口代码完全不用改。
- 如果你是直接传原始的文本内容(包括JSON格式的配置字符串),选
text/plain最符合语义,不需要做额外的序列化转义。 - 如果你是在传标准的JSON结构对象,才需要用
application/json。
内容的提问来源于stack exchange,提问作者Dravis85

