【问题标题】:"400/The input was not valid" when calling ASP.NET Core Web API调用 ASP.NET Core Web API 时出现“400/输入无效”
【发布时间】:2019-01-14 18:48:37
【问题描述】:

我正在使用 postman 测试我的 Web API,并在 Postman 中返回“400 错误请求”或“输入无效”。我的动作第一行的断点没有被击中。我怎样才能弄清楚幕后发生了什么?

我会显示 Postman 的屏幕截图,但我无法上传图片。它只是一个为 Body 指定了几个字段的 POST。这是网址:

http://localhost:52126/api/v1/itinerary

下面是动作:

[HttpPost]
[Route("api/v1/itinerary")]
public async Task<ActionResult> AddItineraryAsync([FromBody] Itinerary itinerary)
{
    if (!ModelState.IsValid) // Break point on this line not getting hit!
    {
        return BadRequest(ModelState);
    }

    await Logic.AddItineraryAsync(itinerary);

    return Ok();
}

最初,我没有为操作指定 [FromBody]。这两种方式都行不通。我可以检查什么来弄清楚发生了什么?

澄清(回应 Chris Pratt):

我正处于编写我的第一个移动应用程序的早期阶段,作为一个自下而上的人,我首先要让一些 Web API 调用正常工作。我假设我会将 JSON 从移动应用程序传递到此服务器层。

我没有在这个 Web API 项目中做任何与防伪令牌有关的事情,所以我认为这些都没有发挥作用……除非那是来自 Postman 的东西。

从动作中删除参数确实允许执行落到我的断点,因此错误似乎与 ASP.NET 尝试绑定有关。

在 Postman 中挖掘了一下之后,我确实看到标题为 Content-Type 指定了 x-www-form-urlencoded。按照您的建议,我将其更改为application/json。然而,这似乎并没有什么不同。

更多信息:

在尝试了 Carl 下面的建议后,我获得了更多信息。执行下降到动作中,我查看了 Postman 传递的内容。这里是:

----------------------------179455694862693501539465
Content-Disposition: form-data; name="StartPoint"

Tacoma
----------------------------179455694862693501539465
Content-Disposition: form-data; name="EndPoint"

Portland
----------------------------179455694862693501539465
Content-Disposition: form-data; name="TravelDate"

2018-8-21 07:00:00 AM
----------------------------179455694862693501539465
Content-Disposition: form-data; name="Name"

Test Itinerary
----------------------------179455694862693501539465
Content-Disposition: form-data; name="UserAccountId"

2
----------------------------179455694862693501539465
Content-Disposition: form-data; name="Comment"

Just doin' some testing.
----------------------------179455694862693501539465--

Json 反序列化失败:

JsonReaderException: Input string &#x27;----------------------------179455694862693501539465&#x27; is not a valid number.

这些数字是什么?它们来自哪里?

【问题讨论】:

  • 对于179455694862693501539465,您似乎正在使用邮递员和application/x-www-form-urlencoded 作为Content-Type。我建议您按照以下步骤操作: 1. 使用AddItineraryAsync([FromBody] Itinerary itinerary) 保留您的api; 2.清除邮递员中的标题 3.Body 选项卡选择rawJSON(application/json) 4.输入有效的json字符串或仅使用{} 5.确保除了application/json 之外没有其他标题Content-Typeheaders 选项卡中。 6.发送请求,检查api方法是否会被命中。
  • 刚刚看到你的评论,爱德华。昨晚给邮递员发了邮件,得到了回复。他们告诉我同样的事情。我需要选择 Raw 并输入 JSON 而不是使用 Body 选项卡。另外,你是对的。这适用于 ASP.NET 的标准绑定。

标签: c# postman asp.net-core-webapi


【解决方案1】:

ModelState 仅在能够成功反序列化帖子正文/绑定时才被验证。

您的问题没有具体说明,但听起来好像您以x-www-form-urlencoded 发帖。如果是这种情况,您应该拥有[FromBody]。但是,请记住这是一种非此即彼的情况,因此如果您最终希望通过 JSON 发布,那么您应该保留该属性并改为从 Postman 发布 JSON。

除此之外,请确保您没有使用防伪令牌验证,或者您在请求中发布了有效的令牌。防伪验证失败会使请求短路并立即返回 400。

如果您发布 JSON,请确保您的 JSON 有效。如果 JSON 无效,您将立即获得 400。

【讨论】:

  • 克里斯,感谢您给我一些检查。我在上面的问题中添加了更多信息。还是不行。
【解决方案2】:

来自评论的解决方案:

对于 179455694862693501539465,您似乎正在使用 PostMan 并将 application/x-www-form-urlencoded 作为 Content-Type。
我建议您按照以下步骤操作:
1. 使用 AddItineraryAsync([FromBody] Itinerary itinerary);
保留您的 api 2.在邮递员中清除您的标题
3. 正文选项卡选择原始 JSON(application/json)
4. 输入有效的 json 字符串或仅使用 {}
5. 确保在 headers 选项卡中除了 application/json 作为 Content-Type 之外没有其他标头。
6.发送请求,检查api方法是否会被命中。

【讨论】:

  • 我的问题不是我使用的表单,而是因为我使用的是[ ],所以我删除了它,然后按照你说的“输入有效的json字符串或只使用{} "
【解决方案3】:

我像您的[FromBody] Itinerary itinerary 一样尝试它,但得到了解决。 2.1 框架有问题https://github.com/aspnet/Mvc/issues/7609https://github.com/aspnet/Mvc/issues/7799。我在 2.1 中得到了这个工作:客户端 javascript 没有改变:

var payload = JSON.stringify({ "name": document.getElementById('firstname').value, "email": document.getElementById('email').value, "captcha": grecaptcha.getResponse() });
var oReq = new XMLHttpRequest();
oReq.ContentType = "application/json";

oReq.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {

        document.getElementById("update").innerHTML = this.responseText;
    }
    else document.getElementById("update").innerHTML = "not 4&200! : " + this.responseText;
};

oReq.open('POST', 'api/u');
oReq.send(payload);

控制器有:

[Route("api/[controller]")]
//  [ApiController] // works either way
public class UController : ControllerBase
{
    [HttpPost]
    public async Task<string> signUp()
    {
        String body;
        using (StreamReader reader = new StreamReader(Request.Body, Encoding.UTF8))
        {
            body = await reader.ReadToEndAsync();
        }

        UserSignup user = JsonConvert.DeserializeObject<UserSignup>(body);

        return user.email;
    }
}

即将上线https://github.com/Hover-Us/

【讨论】:

  • 没有足够的代表评论 OP @birdus。 “这些数字是什么?它们来自哪里?”你是从 Postman 发送 JSON 吗?看起来你有Content-Type: multipart/form-data;boundary="----------------------------179455694862693501539465"
  • 我正在尝试从 Postman 发送 JSON。在我在顶部输入 API 调用 URL 的主页上,我输入了所有参数,并在 URL 正下方选择了 Body。在Body 的左侧,我单击了Headers 并为Content-Type 输入application/json。我找错地方了吗?
  • 回到我在代码中的断点并检查了 Request。您对 Content-Type 是正确的。只需要弄清楚在哪里改变它。
猜你喜欢
  • 2020-02-01
  • 1970-01-01
  • 2017-12-07
  • 2013-04-24
  • 2021-10-28
  • 2020-09-07
  • 2021-02-16
  • 2019-05-06
  • 2019-04-27
相关资源
最近更新 更多