发送一个表单POST HTTP请求(Content-Type: application/x-www-form-urlencoded)到下面的控制器,结果是一个HTTP 415不支持的媒体类型响应。

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

表单post 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

这在过去是与ASP一起工作的。NET MVC 5在。NET 4.6。


当前回答

请遵循以下步骤:

添加到发送请求头内容类型字段: axios。邮报》(' /订单/ ',orderId、 { headers: {'Content-Type': 'application/json'} }) 使用axios发送的每个数据(简单或复杂类型)都不应该放置任何额外的括号(axios。post('/Order/', orderId,…))。

警告!字符串类型有一个例外——在发送前对其进行stringify (axios。post('/Order/', JSON.stringify(address),…))。

添加方法到控制器: (HttpPost) ([FromBody]int orderId) { 还好(); }

其他回答

这个问题可能是因为MVC的MW。你必须在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;
            });

另一个值得注意的陷阱是确保你没有使用下面的消费属性来装饰控制器:

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

如果上载不是JSON,这将失败与415不支持的媒体类型。

“我的一个朋友”最近被这样的事情所揭穿:

public class MyFileUploadController : MyCustomController {

}

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

}

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

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

ASP。NET核心:[FromBody] vs [FromForm]

当您试图将表单字段数据发送给ASP时,不支持的媒体类型错误很常见。NET通过POST,但使用它的专门WebAPI端点处理程序之一,不接受名值对。[FromBody]是问题所在,不接受传统的HTML5表单字段名值对,但需要通过JSON的JavaScript POST。请继续读下去……

使用[FromForm]进行传统的HTML表单后捕获。它可以用于从名称-值对(从存储在Http请求正文中的POST HTML数据)中捕获单个表单字段值,也可以用于在一个批处理中捕获所有字段值。但是你必须为每一个修改WebAPI c#方法。

在传统的HTML表单字段POST到服务器中,在提交时,浏览器使用发送到服务器的请求的Http主体发送表单的所有名称-值对。因此,提交以下HTML并将其方法更改为POST将所有字段以纯文本的形式发送给服务器:

    <form id="form1" name="form1" method="post" action="https://localhost:44347/api/test/edit">
        <input type="text" id="field1" name="field1" size="20" value="" /><br />
        <input type="text" id="field2" name="field2" size="20" value="" /><br />
        <input type="text" id="field3" name="field3" size="20" value="" /><br />
        <!-- SEND POST as traditional Name-Value pair. -->
        <button id="formbutton" name="formbutton" form="form1" value="submit">Form Submit (POST)</button>
    </form>

在ASP. xml中仅捕获一个表单字段值。你可以使用[FromForm]…

[HttpPost]
public string EditByPost([FromForm] string myfield1)
{
  return "Success: " + myfield1;
}

...或者你可以捕获所有的表单字段作为一个集合使用c#匹配对象…

[HttpPost]
public ActionResult EditByPost([FromForm] Form1 form)
{
   // Here I am just returning the full set of form fields
   // back as a JSON object.
   return new JsonResult(form);
}

// Here is the C# Class I created that matches the HTML
// form fields being captured by [FormForm]:
public class Form1
{
  public string field1 { get; set; }
  public string field2 { get; set; }
  public string field3 { get; set; }
}

奇怪的生物叫[FromBody]

[FromBody] is different. It breaks the traditional HTML form field POST that has worked the same for 20+ years and uses something different! It works much like [FromForm] does, but it is a new design, requiring JavaScript and its form data formatted in JSON with the JSON mime-type or "Content-Type" Http header in the Request that is sent to the server. It is also sent via the Http POST inside the body or payload section of the Request, but formatted as JSON with the 'application/json' Content-type, telling your ASP.NET WebAPI Core endpoint method to parse JSON objects, not traditional HTML form name-value pairs.

因为常规的HTML4/HTML5表单不能POST JSON或其内容类型,你必须使用JavaScript技巧,并在c#中使用[FromBody]装饰你的属性来做到这一点。这就是让使用普通HTML的人感到困惑的地方。

下面的示例现在监听JSON表单数据,而不是名称-值对。这并不是很明显,因为它看起来和[FromForm]版本一样…

[HttpPost]
public ActionResult EditByPost([FromBody] Form1 form)
{
    return new JsonResult(form);
}

要将带有JSON的表单字段数据发送到上面的[FromBody] WebAPI,您必须使用JavaScript并手动从HTML中提取表单字段,然后将它们与JSON数据和JSON内容类型一起发送到服务器。现在,大多数现代JavaScript api只是绕过HTML,将原始JSON数据存储并发送到监听的WebAPI POST。

下面,我将使用一个新的ECMAScript/JavaScript技巧来提取上面使用的相同的HTML表单字段值。然后,我使用async-await调用Promise对象(由fetch包装),手动为侦听服务器添加正确的JSON头内容类型,然后绕过HTML直接将这个新表单数据包POST到服务器。这可以添加到上面的HTML提交按钮中,作为关闭HTML提交过程并使用JavaScript的函数:

async function JavaScriptPOST() {
  var form = document.getElementById('form1');
  var myfield1 = form.querySelector('#field1').value;
  var myfield2 = form.querySelector('#field2').value;
  var myfield3 = form.querySelector('#field3').value;
  const response = await fetch('https://example.com/editbypost',
  {
    method: 'POST',
    body: JSON.stringify({
      field1: myfield1,
      field2: myfield2,
      field2: myfield3
    }),
    headers: {
      'Content-type':'application/json; charset=UTF-8',
    }
  }).then(...);
}

要意识到一件事,HTML仍然是世界上的主导技术。大多数HTML表单仍然使用传统的post名称-值技术发布数据。像这样的JavaScript技巧正在成为新的规范,但它们不会取代原始的HTML表单技术,也不会仅通过脚本来取代。

但是,当这些技术供应商根据几十年来的工作方式重写技术堆栈时,了解旧技术的工作方式总是有帮助的。可悲的是,它们并没有让开发人员更容易、更快或更直观,而是像这张海报一样让人困惑。

这是我的案子:它跑了 环境: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>