简体   繁体   English

将表单数据从 React 发送到 ASP.NET Core API

[英]Send form data from React to ASP.NET Core API

I editted the whole question because it was very long and confusing.我编辑了整个问题,因为它很长而且令人困惑。

Clear, concise new question清晰简洁的新问题

I was sending all data from my forms as a stringified JSON, but now I need to append a file, so I can no longer do this.我将表单中的所有数据作为字符串化 JSON 发送,但现在我需要附加一个文件,所以我不能再这样做了。 How do I send my form data from React to an ASP.NET Core API in a format that allows appending files?如何以允许附加文件的格式将表单数据从 React 发送到 ASP.NET Core API?

Old question老问题

I have several forms working perfectly: I send the data using fetch from React and receive it correctly as body in my ASP.NET Core API.我有几种工作正常的表单:我使用 React 中的 fetch 发送数据,并在我的 ASP.NET Core API 中正确接收它作为正文。

However, I need to send files now, and I don't know how to append them since I am just sending all of my content in a strinfified JSON.但是,我现在需要发送文件,而且我不知道如何附加它们,因为我只是将我的所有内容都发送到一个精简的 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);
    }
);

I tried sending a FormData object built like this instead of the JSON.stringify(body) .我尝试发送这样构建的 FormData 对象而不是JSON.stringify(body)

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

But when I send this object instead of the stringified JSON I always get null for all the values in ASP.NET Core.但是当我发送这个对象而不是字符串化的 JSON 时,对于 ASP.NET Core 中的所有值,我总是得到 null。

I also tried sending this:我也试过发送这个:

URLSearchParams(data)

And this:和这个:

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

And I tried different combinations of headers with every type of data encoding:我尝试了每种类型的数据编码的不同标头组合:

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

I also tried getting the data from ASP.NET with both [FromBody] and [FromForm] .我还尝试使用[FromBody][FromForm]从 ASP.NET 获取数据。

I think I have tried every possible combination of all the options I have explained above, with no result.我想我已经尝试了上面解释过的所有选项的所有可能组合,但没有结果。 I always get null values in my API.我总是在我的 API 中得到空值。

Edit:编辑:

Right now, I am not even trying to send a file.现在,我什至没有尝试发送文件。 I am trying to successfully send common data in the proper format before trying to attach a file.在尝试附加文件之前,我正在尝试以正确的格式成功发送通用数据。 I don't know if I should change the title of the question.我不知道我是否应该更改问题的标题。

This is my API code:这是我的 API 代码:

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

The class Credentials :Credentials

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

The object body from React looks like this: React 的对象body如下所示:

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

A bit more time now.现在还有一点时间。 (10 fish caught.) I notice from your code you had used the header "multipart/formdata", It should have a hyphen; (捕获了 10 条鱼。)我从您的代码中注意到您使用了标题“multipart/formdata”,它应该有一个连字符; "multipart/form-data". “多部分/表单数据”。

On my API I am specifying that it consumes the same type: [Consumes("multipart/form-data")]在我的 API 上,我指定它使用相同的类型: [Consumes("multipart/form-data")]

I am not clear what the .net core defaults are and whether it should automatically de-serialise the form data but specifying it should rule out any ambiguity.我不清楚 .net 核心默认值是什么以及它是否应该自动反序列化表单数据,但指定它应该排除任何歧义。

With my code I am sending a file with some parameters.使用我的代码,我正在发送一个带有一些参数的文件。 On the api side it looks like:在 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)

.... Then on the client side it looks like: ....然后在客户端它看起来像:

  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,
  })

With the file coming from文件来自

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

(from my React component) (来自我的 React 组件)

My whole question was a mess and, in my case, the problem was the for loop.我的整个问题都是一团糟,就我而言,问题在于for循环。 However, I will try to explain clearly what I needed because there is a lot of missleading information online about how to submit a form to an API with React.但是,我将尝试清楚地解释我需要什么,因为网上有很多关于如何使用 React 将表单提交到 API 的误导性信息。

Solution解决方案

Backend后端

In the backend, accept POST petitions and get the data with FromForm .在后端,接受 POST 请求并使用FromForm获取数据。 If you need to use credentials, it is probably better to pass them through headers instead of putting them as hidden inputs inside every single form.如果您需要使用凭据,最好通过标题传递它们,而不是将它们作为隐藏输入放在每个表单中。

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

If you bind an object, the properties must have the same name as the ones you are sending from the frontend and must have a public setter .如果绑定对象,则属性必须与从前端发送的属性名称相同,并且必须具有公共 setter

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

Frontend前端

Send the data as FormData .将数据作为FormData发送。 To do this, you can follow this tutorial .为此,您可以按照本教程进行操作。 That way, you won't need to worry about handling input changes and formatting your data before submitting it.这样,您无需担心在提交数据之前处理输入更改和格式化数据。

However, if your data is already in a plain JavaScript object, you can transform it in a FormData as shown below.但是,如果您的数据已经在纯 JavaScript 对象中,您可以将其转换为FormData ,如下所示。

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

Nonetheless, this is very basic and if you have a complex object (with arrays, nested objects, etc) you will need to handle it differently.尽管如此,这是非常基本的,如果您有一个复杂的对象(包含数组、嵌套对象等),您将需要以不同的方式处理它。

Finally, I used fetch to call my API.最后,我使用fetch来调用我的 API。 If you use it, it is important to NOT set the Content-Type header , because you will be overwritting the one that fetch automatically chooses for you, which will be the right one in most cases.如果您使用它,请务必不要设置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);
    }
);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM