简体   繁体   English

如何使用 fetch api 发布表单数据?

[英]How do I post form data with fetch api?

My code:我的代码:

fetch("api/xxx", {
    body: new FormData(document.getElementById("form")),
    headers: {
        "Content-Type": "application/x-www-form-urlencoded",
        // "Content-Type": "multipart/form-data",
    },
    method: "post",
}

I tried to post my form using fetch api, and the body it sends is like:我尝试使用 fetch api 发布我的表单,它发送的正文如下:

-----------------------------114782935826962
Content-Disposition: form-data; name="email"

test@example.com
-----------------------------114782935826962
Content-Disposition: form-data; name="password"

pw
-----------------------------114782935826962--

(I don't know why the number in boundary is changed every time it sends...) (我不知道为什么每次发送时边界中的数字都会改变......)

I would like it to send the data with "Content-Type": "application/x-www-form-urlencoded", what should I do?我希望它使用“Content-Type”发送数据:“application/x-www-form-urlencoded”,我该怎么办? Or if I just have to deal with it, how do I decode the data in my controller?或者如果我只需要处理它,我如何解码控制器中的数据?


To whom answer my question, I know I can do it with:谁回答我的问题,我知道我可以做到:

fetch("api/xxx", {
    body: "email=test@example.com&password=pw",
    headers: {
        "Content-Type": "application/x-www-form-urlencoded",
    },
    method: "post",
}

What I want is something like $("#form").serialize() in jQuery (w/o using jQuery) or the way to decode mulitpart/form-data in controller.我想要的是 jQuery 中的 $("#form").serialize() (不使用 jQuery)或在控制器中解码 mulitpart/form-data 的方式。 Thanks for your answers though.不过感谢您的回答。

To quote MDN on FormData (emphasis mine):FormData上引用 MDN (强调我的):

The FormData interface provides a way to easily construct a set of key/value pairs representing form fields and their values, which can then be easily sent using the XMLHttpRequest.send() method. FormData接口提供了一种方法来轻松构造一组表示表单字段及其值的键/值对,然后可以使用XMLHttpRequest.send()方法轻松发送。 It uses the same format a form would use if the encoding type were set to "multipart/form-data" .如果编码类型设置为"multipart/form-data" ,它使用与表单相同的格式

So when using FormData you are locking yourself into multipart/form-data .因此,当使用FormData时,您会将自己锁定在multipart/form-data中。 There is no way to send a FormData object as the body and not sending data in the multipart/form-data format.无法将FormData对象作为正文发送,也不multipart/form-data格式发送数据。

If you want to send the data as application/x-www-form-urlencoded you will either have to specify the body as an URL-encoded string, or pass a URLSearchParams object.如果要将数据作为application/x-www-form-urlencoded发送,则必须将正文指定为 URL 编码字符串,或传递URLSearchParams对象。 The latter unfortunately cannot be directly initialized from a form element.遗憾的是后者不能直接从form元素初始化。 If you don't want to iterate through your form elements yourself (which you could do using HTMLFormElement.elements ), you could also create a URLSearchParams object from a FormData object:如果您不想自己遍历表单元素(可以使用HTMLFormElement.elements进行),您还可以从FormData对象创建URLSearchParams对象:

const data = new URLSearchParams();
for (const pair of new FormData(formElement)) {
    data.append(pair[0], pair[1]);
}

fetch(url, {
    method: 'post',
    body: data,
})
.then(…);

Note that you do not need to specify a Content-Type header yourself.请注意,您不需要自己指定Content-Type标头。


As noted by monk-time in the comments, you can also create URLSearchParams and pass the FormData object directly, instead of appending the values in a loop:正如评论中的和尚时间所指出的,您还可以创建URLSearchParams并直接传递FormData对象,而不是在循环中附加值:

const data = new URLSearchParams(new FormData(formElement));

This still has some experimental support in browsers though, so make sure to test this properly before you use it.不过,这在浏览器中仍有一些实验性支持,因此请确保在使用之前对其进行正确测试。

Client客户

Do not set the content-type header.不要设置内容类型标头。

// Build formData object.
let formData = new FormData();
formData.append('name', 'John');
formData.append('password', 'John123');

fetch("api/SampleData",
    {
        body: formData,
        method: "post"
    });

Server服务器

Use the FromForm attribute to specify that binding source is form data.使用FromForm属性来指定绑定源是表单数据。

[Route("api/[controller]")]
public class SampleDataController : Controller
{
    [HttpPost]
    public IActionResult Create([FromForm]UserDto dto)
    {
        return Ok();
    }
}

public class UserDto
{
    public string Name { get; set; }
    public string Password { get; set; }
}

Use FormData and fetch to grab and send data使用FormDatafetch抓取和发送数据

fetch(form.action, {method:'post', body: new FormData(form)});

 function send(e,form) { fetch(form.action, {method:'post', body: new FormData(form)}); console.log('We send post asynchronously (AJAX)'); e.preventDefault(); }
 <form method="POST" action="myapi/send" onsubmit="send(event,this)"> <input hidden name="csrfToken" value="a1e24s1"> <input name="email" value="a@b.com"> <input name="phone" value="123-456-789"> <input type="submit"> </form> Look on chrome console>network before/after 'submit'

You can set body to an instance of URLSearchParams with query string passed as argument您可以将body设置为URLSearchParams的实例,并将查询字符串作为参数传递

fetch("/path/to/server", {
  method:"POST"
, body:new URLSearchParams("email=test@example.com&password=pw")
})

 document.forms[0].onsubmit = async(e) => { e.preventDefault(); const params = new URLSearchParams([...new FormData(e.target).entries()]); // fetch("/path/to/server", {method:"POST", body:params}) const response = await new Response(params).text(); console.log(response); }
 <form> <input name="email" value="test@example.com"> <input name="password" value="pw"> <input type="submit"> </form>

With fetch api it turned out that you do NOT have to include headers "Content-type": "multipart/form-data".使用 fetch api,事实证明您不必包含标题“Content-type”:“multipart/form-data”。

So the following works:所以以下工作:

let formData = new FormData()
formData.append("nameField", fileToSend)

fetch(yourUrlToPost, {
   method: "POST",
   body: formData
})

Note that with axios I had to use the content-type.请注意,使用 axios 我必须使用内容类型。

👨‍💻These can help you: 👨‍💻这些可以帮助你:

let formData = new FormData();
            formData.append("name", "John");
            formData.append("password", "John123");
            fetch("https://yourwebhook", {
              method: "POST",
              mode: "no-cors",
              cache: "no-cache",
              credentials: "same-origin",
              headers: {
                "Content-Type": "form-data"
              },
              body: formData
            });
            //router.push("/registro-completado");
          } else {
            // doc.data() will be undefined in this case
            console.log("No such document!");
          }
        })
        .catch(function(error) {
          console.log("Error getting document:", error);
        });

To add on the good answers above you can also avoid setting explicitly the action in HTML and use an event handler in javascript, using "this" as the form to create the "FormData" object要添加上面的好答案,您还可以避免在 HTML 中明确设置操作并在 javascript 中使用事件处理程序,使用“this”作为创建“FormData”对象的表单

Html form : html格式:

<form id="mainForm" class="" novalidate>
<!--Whatever here...-->
</form>

In your JS :在你的 JS 中:

$("#mainForm").submit(function( event ) {
  event.preventDefault();
  const formData = new URLSearchParams(new FormData(this));
  fetch("http://localhost:8080/your/server",
    {   method: 'POST',
        mode : 'same-origin',
        credentials: 'same-origin' ,
        body : formData
    })
    .then(function(response) {
      return response.text()
    }).then(function(text) {
        //text is the server's response
    });
});

@KamilKiełczewski answer is great if you are okay with the form data format being in form multipart style, however if you need the form submitted in query parameter styles: @KamilKiełczewski 如果您对表单数据格式采用表单多部分样式没问题,那么答案非常好,但是如果您需要以查询参数样式提交的表单:

You can also pass FormData directly to the URLSearchParams constructor if you want to generate query parameters in the way a would do if it were using simple GET submission.如果您想以使用简单 GET 提交的方式生成查询参数,也可以将FormData 直接传递给 URLSearchParams 构造函数

        form = document.querySelector('form')
        const formData = new FormData(form);
        formData["foo"] = "bar";
        const payload = new URLSearchParams(formData)
        fetch(form.action, payload)

" body:FormData " works but there're type complains, also " FormData " sets multipart headers. body:FormData ” 有效,但有类型抱怨,“ FormData ” 设置多部分标题。 To make the things simplier, " body:URLSearchParams " with inline construction and headers set manually may be used :为了使事情变得更简单,可以使用具有内联结构和手动设置标题的“ body:URLSearchParams ”:

function getAccessToken(code) {

    return fetch(tokenURL, 
        {
            method: 'POST',
            headers: {
               'Content-Type': 'application/x-www-form-urlencoded',                 
               'Accept': '*/*' 
            },            
            body: new URLSearchParams({
                'client_id':clientId,    
                'client_secret':clientSecret,
                'code':code,    
                'grant_type': grantType,
                'redirect_uri':'',
                'scope':scope
            })
        }
        )
    .then(
        r => return r.json()
    ).then(
        r => r.access_token
    )
  }

There are instructions on the MDN that the browser will automatically handle Content-Type . MDN 上有关于浏览器将自动处理Content-Type说明。

[A request will also automatically set a Content-Type header if none is set in the dictionary.](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch#body) [如果字典中没有设置,请求也会自动设置 Content-Type 头。](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch#body)

So we don't need to specify 'content-type' when we send a fetch request.所以我们在发送 fetch 请求时不需要指定 'content-type'。

const formData = new FormData();
const fileField = document.querySelector('input[type="file"]');

formData.append('username', 'abc123');
formData.append('avatar', fileField.files[0]);

fetch('https://example.com/profile/avatar', {
  method: 'PUT',
  body: formData
})
.then(response => response.json())
.then(result => {
  console.log('Success:', result);
})
.catch(error => {
  console.error('Error:', error);
});

If set content-type in headers.如果在标题中设置content-type Browser will not try to split formdata in request payload.浏览器不会尝试在请求负载中拆分表单数据。

I'm using fathcer to handle FormData, the same behavior as XHR.我正在使用fathcer来处理FormData,与XHR 的行为相同。

import { formData } from '@fatcherjs/middleware-form-data';
import { json } from '@fatcherjs/middleware-json';
import { fatcher } from 'fatcher';

fatcher({
    url: '/bar/foo',
    middlewares: [json(), formData()],
    method: 'PUT',
    payload: {
        bar: 'foo',
        file: new File()
    },
    headers: {
        'Content-Type': 'multipart/form-data',
    },
})
    .then(res => {
        console.log(res);
    })
    .catch(err => {
        console.error(error);
    });

To post form data with fetch api, try this code it works for me ^_^要使用 fetch api 发布表单数据,试试这个对我有用的代码 ^_^

function card(fileUri) {
let body = new FormData();
let formData = new FormData();
formData.append('file', fileUri);

fetch("http://X.X.X.X:PORT/upload",
  {
      body: formData,
      method: "post"
  });
 }

Use this for a JSON api:将此用于 JSON api:

Send a POST request发送 POST 请求

async function write(param) {
  var zahl = param.getAttribute("data-role");

  let mood = {
    appId: app_ID,
    key: "",
    value: zahl
  };

  let response = await fetch(web_api, {
    method: "POST",
    headers: {
      "Content-Type": "application/json"
    },
    body: JSON.stringify(mood)
  });
  console.log(currentMood);
}

Send a GET request发送 GET 请求

async function get() {

  let response = await fetch(web_api + "/App/" + app_ID, {
    method: "GET",
    headers: {
      "Content-Typ": "application/json"
    }
  });

  let todos = await response.json();

Send a DELETE request发送删除请求

function remove() {
  return fetch(web_api, {
    method: "DELETE"
  }).then(response => {
    if (!response.ok) {
      throw new Error("There was an error processing the request");
    }
  });
}

Send a PUT request发送 PUT 请求

function updateTodo() {
    return fetch(web_api, {
      method: "PUT",
      body: JSON.stringify(todo),
      headers: {
        "Content-Type": "application/json",
      },
    }).then((response) => {
      if (!response.ok) {
         throw new Error("There was an error processing the request");
      }
    });
}

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

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