【问题标题】:Send form data from React to ASP.NET Core API将表单数据从 React 发送到 ASP.NET Core API
【发布时间】:2022-06-14 15:06:08
【问题描述】:

我编辑了整个问题,因为它很长而且令人困惑。

清晰、简洁的新问题

我将表单中的所有数据作为字符串化 JSON 发送,但现在我需要附加一个文件,所以我不能再这样做了。如何以允许附加文件的格式将表单数据从 React 发送到 ASP.NET Core API?

老问题

我有几种完美的表单:我使用 fetch 从 React 发送数据,并在我的 ASP.NET Core API 中正确接收它作为正文。

但是,我现在需要发送文件,但我不知道如何附加它们,因为我只是将我的所有内容都发送到一个精简的 JSON 中。

fetch("localhost/api/test", {
    method: 'POST',
    headers: {
        'Accept': 'application/json',
        'Content-Type': 'application/json'
    },
    body: JSON.stringify(body)
}).then(result => result.json()).then(
    (result) => {
        console.log(result);
    }
);

我尝试发送这样构建的 FormData 对象,而不是 JSON.stringify(body)

let formData = new FormData();
for (var property in body) {
    formData.append(property, body[property]);
}

但是当我发送这个对象而不是字符串化的 JSON 时,ASP.NET Core 中的所有值总是为 null。

我也试过发送这个:

URLSearchParams(data)

还有这个:

let formBody = [];
for (var property in details) {
    var encodedKey = encodeURIComponent(property);
    var encodedValue = encodeURIComponent(details[property]);
    formBody.push(encodedKey + "=" + encodedValue);
}
formBody = formBody.join("&");

我尝试了每种数据编码类型的不同标头组合:

  • 没有标题
  • 'Content-Type': 'multipart/formdata'
  • 'Content-Type': 'application/json'
  • 'Content-Type': 'application/x-www-form-urlencoded'

我还尝试使用 [FromBody][FromForm] 从 ASP.NET 获取数据。

我想我已经尝试了上面解释的所有选项的所有可能组合,但没有结果。我总是在我的 API 中得到空值。

编辑:

现在,我什至没有尝试发送文件。在尝试附加文件之前,我正在尝试以正确的格式成功发送通用数据。我不知道我是否应该更改问题的标题。

这是我的 API 代码:

[HttpPost]
[Route("login")]
public object Login([FromBody] Credentials cred)
{
    // check credentials
    return CustomResult.Ok;
}

班级Credentials

public class Credentials
{
    public string Username { get; set; }
    public string Password { get; set; }
}

来自 React 的对象 body 如下所示:

{
    username: "user",
    password: "pass"
}

【问题讨论】:

  • 能否分享您的APIReact 代码以了解您如何上传图像文件?这样就可以轻松解决了。
  • 我什至没有文件输入。我只是想以不同的方式发送我的数据,因为我无法通过字符串化 JSON 发送文件,或者我可以吗?
  • 您有两种方式,IFormFile Image 或图像为base64,其中图像将作为string 提供
  • 我花了相当长的时间来解决这个问题。使用 Postman 消除关于其前端还是后端的任何不确定性。您可以使用表单数据等来制作请求,然后确保 api 正常工作。一旦没问题,请使用浏览器上的调试工具查看您的客户端代码产生的请求。
  • @NAJ 使用邮递员是最好的选择。后端很好,问题是我用来将值附加到 formData 的for 循环。我在循环之后检查了该对象,它似乎没问题,但我决定尝试将其更改为 Object.keys(data).forEach 并且它起作用了。我仍然不明白为什么,但它有效

标签: javascript c# reactjs asp.net-core fetch-api


【解决方案1】:

现在还有一点时间。 (钓到了 10 条鱼。) 我从您的代码中注意到您使用了标题“multipart/formdata”,它应该有一个连字符; “多部分/表单数据”。

在我的 API 上,我指定它使用相同的类型:[Consumes("multipart/form-data")]

我不清楚 .net 核心的默认设置是什么以及它是否应该自动反序列化表单数据,但指定它应该排除任何歧义。

使用我的代码,我正在发送一个带有一些参数的文件。在 api 方面它看起来像:

    public class FileUpload_Single
    {
        public IFormFile DataFile { get; set; }
        public string Params { get; set; }
    }

    // POST: api/Company (Create New)
    [HttpPost]
    [Authorize(PermissionItem.SimulationData, PermissionAction.Post)]
    [RequestSizeLimit(1024L * 1024L * 1024L)]  // 1 Gb
    [RequestFormLimits(MultipartBodyLengthLimit = 1024L * 1024L * 1024L)] // 1 Gb
    [Consumes("multipart/form-data")]
    public async virtual Task<IActionResult> Post([FromForm] FileUpload_Single data)

.... 然后在客户端它看起来像:

  let formData = new FormData();
  formData.append("DataFile", file);
  formData.append("Params", JSON.stringify(params));
  fetch(apicall, {
    method: "POST",
    mode: "cors",
    headers: {
      Authorization:
        "Bearer " + (localStorage.getItem("token") || "").replace(/['"]+/g, ""),
      Accept: "multipart/form-data",
    },
    body: formData,
  })

文件来自

  const changeHandler = (event) => {
    setSelectedFile(event.target.files[0]);
    setIsSelected(true);
  };

(来自我的 React 组件)

【讨论】:

    【解决方案2】:

    我的整个问题一团糟,就我而言,问题在于for 循环。但是,我将尝试清楚地解释我需要什么,因为网上有很多关于如何使用 React 将表单提交到 API 的误导性信息。

    解决方案

    后端

    在后端,接受 POST 请求并使用FromForm 获取数据。如果您需要使用凭据,最好通过标题传递它们,而不是将它们作为隐藏输入放在每个表单中。

    [HttpPost]
    [Route("test")]
    public object Test([FromHeader] string token, [FromForm] MyDataClass data)
    {
        // check token
        // do something with data
        return CustomResult.Ok;
    }
    

    如果您绑定一个对象,属性必须与您从前端发送的属性同名,并且必须有一个公共设置器

    public class MyDataClass
    {
        public string SomeInfo { get; set; }
        public string SomeOtherInfo { get; set; }
    }
    

    前端

    FormData 发送数据。为此,您可以关注this tutorial。这样一来,您就无需担心在提交数据之前处理输入更改和格式化数据。

    但是,如果您的数据已经在纯 JavaScript 对象中,您可以将其转换为 FormData,如下所示。

    let formData = new FormData();
    Object.keys(data).forEach(function (key) {
        formData.append(key, data[key]);
    });
    

    尽管如此,这是非常基本的,如果您有一个复杂的对象(包含数组、嵌套对象等),您将需要以不同的方式处理它。

    最后,我使用fetch 调用我的API。如果您使用它,请务必不设置Content-Type 标头,因为您将覆盖fetch 自动为您选择的标头,在大多数情况下这将是正确的标头。

    fetch("localhost/api/test", {
        method: 'POST',
        headers: {
            'Token': "dummy-token"
            // DON'T overwrite Content-Type header
        },
        body: formData
    }).then(result => result.json()).then(
        (result) => {
            console.log(result);
        }
    );
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-10-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-12-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多