【问题标题】:ASP.NET Core form POST results in a HTTP 415 Unsupported Media Type responseASP.NET Core 表单 POST 导致 HTTP 415 Unsupported Media Type 响应
【发布时间】:2017-11-16 06:02:25
【问题描述】:

向以下控制器发送表单 POST HTTP 请求 (Content-Type: application/x-www-form-urlencoded) 会导致 HTTP 415 Unsupported Media Type 响应。

public class MyController : Controller
{
    [HttpPost]
    public async Task<IActionResult> Submit([FromBody] MyModel model)
    {
        //...
    }
}

表单发布 HTTP 标头:

POST /submit HTTP/1.1
Host: example.com:1337
Connection: keep-alive
Content-Length: 219
Pragma: no-cache
Cache-Control: no-cache
Origin: https://example.com:1337
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36
Content-Type: application/x-www-form-urlencoded
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Referer: https://example.com:1337/submit
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.8,nl;q=0.6

这曾经在 .NET 4.6 上与 ASP.NET MVC 5 一起使用。

【问题讨论】:

  • 您不必使用 [FromForm] "Submit(MyModel model)" 也可以正确获取模型。

标签: c# asp.net-core asp.net-core-mvc


【解决方案1】:

对于表单,使用 [FromForm] 属性而不是 [FromBody] 属性。

以下控制器适用于 ASP.NET Core 1.1:

public class MyController : Controller
{
    [HttpPost]
    public async Task<IActionResult> Submit([FromForm] MyModel model)
    {
        //...
    }
}

注意:如果您的控制器带有 [ApiController] 注释,则需要 [FromXxx]。对于普通视图控制器,它可以省略。

【讨论】:

    【解决方案2】:

    您可以使用[FromBody],但您需要将请求的Content-Type标头设置为application/json,即

    Content-Type: application/json
    

    【讨论】:

    • 这就是为什么这个问题特别提到了一个 form POST,内容类型为application/x-www-form-urlencoded。就像 HTML 页面上的 &lt;form&gt; 一样。
    • 这对我很有帮助,因为我提交的是对象,而不是表单。接受的答案对于 OP 来说是最正确的,他已经为 [FromForm] 使用了正确的内容类型。不过,我很高兴这个也在这里。 :)
    • 这根本没有回答问题。问题是如何让服务器支持表单主体,而不是如何告诉所有客户端停止发送它们!
    • 等等,这是否意味着不可能从不同于application/json 的请求正文中提取内容,例如application/text? @BartVerkoeijen 有什么想法吗?
    【解决方案3】:

    首先需要在Headers中指定Content-Type,例如可以是application/json

    如果你设置application/json内容类型,那么你需要发送一个json。

    所以在您请求的body 中,您将发送的不是form-data,不是x-www-for-urlencoded,而是raw json,例如{"Username": "user", "Password": "pass"}

    您可以使示例适应各种内容类型,包括您要发送的内容。

    您可以使用 Postman 或 curl 之类的工具来玩这个。

    【讨论】:

      【解决方案4】:

      作为良好答案的补充,您不必使用[FromForm] 在控制器中获取表单数据。框架根据您的需要自动将表单数据转换为模型。你可以像下面这样实现。

      [HttpPost]
      public async Task<IActionResult> Submit(MyModel model)
      {
          //...
      }
      

      【讨论】:

      • 不是我看到的。
      • 我已经测试过了,它工作正常,你的代码可能有另一个问题
      • 这解决了我的问题。我正在使用其中包含字段和文件的 FormData 对象,[FromForm] 或 [FromBody] 不起作用。删除它们并且它起作用了。 (Asp.Net MVC Core 2.1 后面,vanilla js 前面)。 Gist Here.
      • 对我来说,我有一个 [FromQuery] 参数,但我没有将 Content-Type 指定为 application/json - 在我的请求中添加它,也可以使用 [FromQuery] 参数。
      • 我已经更新了接受的答案,但@hasan 和@François 都是正确的。仅当控制器是 ApiController 时才需要 [FromForm] 属性。
      【解决方案5】:

      这是我的情况:它正在运行 环境:AspNet Core 2.1 控制器:

      public class MyController
      {
          // ...
      
          [HttpPost]
          public ViewResult Search([FromForm]MySearchModel searchModel)
          {
              // ...
              return View("Index", viewmodel);
          }
      }
      

      查看:

      <form method="post" asp-controller="MyController" asp-action="Search">
          <input name="MySearchModelProperty" id="MySearchModelProperty" />
          <input type="submit" value="Search" />
      </form>
      

      【讨论】:

        【解决方案6】:

        问题可能是由于 MVC MW.you 必须在 MVC 选项中设置 formatterType:

        services.AddMvc(options =>
                    {
                        options.UseCustomStringModelBinder();
                        options.AllowEmptyInputInBodyModelBinding = true;
                        foreach (var formatter in options.InputFormatters)
                        {
                            if (formatter.GetType() == typeof(SystemTextJsonInputFormatter))
                                ((SystemTextJsonInputFormatter)formatter).SupportedMediaTypes.Add(
                                    Microsoft.Net.Http.Headers.MediaTypeHeaderValue.Parse("text/plain"));
                        }
                    }).AddJsonOptions(options =>
                    {
                        options.JsonSerializerOptions.PropertyNameCaseInsensitive = true;
                    });
        

        【讨论】:

        • options.UseCustomStringModelBinder() 在哪里可用?我在任何地方都没有找到它的文档。
        【解决方案7】:

        “HTTP 415 不支持的媒体类型响应”源自请求标头中的 Content-Type。例如在 axios 的 javascript 中:

        Axios({
                    method: 'post',
                    headers: { 'Content-Type': 'application/json'},
                    url: '/',
                    data: data,  // an object u want to send
                  }).then(function (response) {
                    console.log(response);
                  });
        

        【讨论】:

          【解决方案8】:

          按照以下步骤操作:

          1. 添加到发送请求头Content-Type字段:

             axios.post(`/Order/`, orderId,
             {
                 headers: {'Content-Type': 'application/json'}
             })
            
          2. 使用 axios 发送的每个数据(简单或复杂类型)都应放置不带任何额外括号 (axios.post('/Order/', orderId, ...))。

          警告! string 类型有一个例外 - 在发送之前将其字符串化 (axios.post('/Order/', JSON.stringify(address), ...))。

          1. 向控制器添加方法:

            [HttpPost]
            public async Task<IActionResult> Post([FromBody]int orderId)
            {
                return Ok();
            }
            

          【讨论】:

            【解决方案9】:

            另一个值得注意的陷阱是确保您没有使用Consume Attribute 来装饰控制器,如下所示:

            [Produces("application/json")]
            [Consumes("application/json")]
            public class MyController : Controller
            

            如果上传不是 JSON,这将失败并显示 415 Unsupported Media Type

            “我的一个朋友”最近被这样的事情抓住了:

            public class MyFileUploadController : MyCustomController {
            
            }
            
            [Produces("application/json")]
            [Consumes("application/json")]
            public class MyCustomController : ControllerBase {
            
            }
            

            【讨论】:

              【解决方案10】:

              就我而言,我收到了 HTTP 415 Unsupported Media Type 响应,因为我将内容类型指定为 TEXT 而不是 JSON,因此只需更改类型即可解决问题。 请在以下博客文章中更详细地查看解决方案: https://www.howtodevelop.net/article/20/unsupported-media-type-415-in-aspnet-core-web-api

              【讨论】:

                【解决方案11】:

                在我的情况下,收到了 415 个不受支持的媒体类型,因为我使用了 new FormData() 并使用 axios.post(...) 发送它,但没有设置 headers: {content-type: 'multipart/form-data'}。我也必须在服务器端做同样的事情:

                [Consumes("multipart/form-data")]
                public async Task<IActionResult> FileUpload([FromForm] IFormFile formFile) { ... }
                

                【讨论】:

                • 此时它不起作用,我仍然有一个带有[Consumes("multipart/form-data")] 的 415,没有每个参数都为 null :( 为什么这么难做这样一个基本的事情..
                • @moff452 使用 multipart 你必须使用自定义模型绑定器(如果你使用自定义模型),否则你最终会得到空值。
                • 最后,我不需要装饰器或 [FromForm],我只是忘记将 {get;set;} 添加到每个属性...现在它就像一个魅力:)
                【解决方案12】:

                使用.NET 5,我有一个如下所示的 .NET API 控制器方法:

                [HttpPost("{rootEntity}/{id}")]
                public ActionResult Post(RootEntity rootEntity, int id, [FromBody] string message)
                {
                    ...
                }
                

                我有这个要求:

                POST /api/Comment/1/1 HTTP/1.1
                Host: localhost:12345
                Content-Type: text/plain
                Content-Length: 4
                
                test
                

                导致以下状态代码响应:415 Unsupported Media Type

                {
                    "type": "https://tools.ietf.org/html/rfc7231#section-6.5.13",
                    "title": "Unsupported Media Type",
                    "status": 415,
                    "traceId": "00-e7ca54e9f313c24699c3ca4697b9363d-be4719bd10735245-00"
                }
                

                然后我切换到Content-Type: application/json,就像@BjornBailleul 的回答所说,但得到了这个错误:

                {
                    "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
                    "title": "One or more validation errors occurred.",
                    "status": 400,
                    "traceId": "00-0549e2c73842c249a93c8dc2f817e250-796e99fc0000224d-00",
                    "errors": {
                        "$": [
                            "'test' is an invalid JSON literal. Expected the literal 'true'. Path: $ | LineNumber: 0 | BytePositionInLine: 1."
                        ]
                    }
                }
                

                还可以将字符串用引号括起来,如下所示:"test"

                完成工作请求:

                POST /api/Comment/1/1 HTTP/1.1
                Host: localhost:12345
                Content-Type: application/json
                Content-Length: 6
                
                "test"
                

                【讨论】:

                • 如果您投反对票,请说明原因,否则很难改进答案。
                猜你喜欢
                • 1970-01-01
                • 2021-07-16
                • 1970-01-01
                • 2020-05-05
                • 1970-01-01
                • 1970-01-01
                • 2017-08-05
                • 2019-11-08
                • 1970-01-01
                相关资源
                最近更新 更多