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

Zac*_*ack 82 javascript fetch-api

我的代码:

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

我尝试使用fetch api发布我的表单,它发送的正文如下:

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

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

pw
-----------------------------114782935826962--
Run Code Online (Sandbox Code Playgroud)

(我不知道为什么每次发送边界的数字都会改变...)

我希望用"Content-Type"发送数据:"application/x-www-form-urlencoded",我该怎么办?或者,如果我只需处理它,我如何解码控制器中的数据?


谁回答我的问题,我知道我可以做到:

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

我想要的是像$("#form").jQuery中的serialize()(没有使用jQuery)或者在控制器中解码mulitpart/form-data的方法.谢谢你的回答.

pok*_*oke 102

引用MDNFormData(强调我的):

所述FormData接口提供了一种容易地构成一组表示表单字段和它们的值的键/值对,然后可以使用能够容易地发送的XMLHttpRequest.send()方法.如果编码类型设置为,则使用与表单相同的格式"multipart/form-data".

因此,在使用时,FormData您将锁定自己multipart/form-data.无法将FormData对象作为正文发送,也无法multipart/form-data格式发送数据.

如果要发送数据,则application/x-www-form-urlencoded必须将主体指定为URL编码的字符串,或传递URLSearchParams对象.遗憾的是,后者不能直接从form元素初始化.如果您不想自己遍历表单元素(可以使用它HTMLFormElement.elements),您还可以URLSearchParamsFormData对象创建对象:

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

fetch(url, {
    method: 'post',
    body: data,
})
.then(…);
Run Code Online (Sandbox Code Playgroud)

请注意,您无需自己指定Content-Type标题.


正如评论中monk-time所述,您还可以直接创建URLSearchParams并传递FormData对象,而不是在循环中附加值:

const data = new URLSearchParams(new FormData(formElement));
Run Code Online (Sandbox Code Playgroud)

这仍然在浏览器中有一些实验支持,因此请确保在使用之前正确测试.

  • 您也可以直接在构造函数中使用对象或只是`FormData`而不是循环:`new URLSearchParams(new FormData(formElement))` (9认同)
  • 抱歉,这不是抱怨,只是给将来会阅读本文的每个人的注释。 (4认同)
  • 如果您需要发布 FormData,则无需使用 `URLSearchParams` fetch(url, { method: 'post', body: new FormData(form_element), }) (2认同)

reg*_*uld 42

客户

不要设置content-type标头.

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

fetch("api/SampleData",
    {
        body: formData,
        method: "post"
    });
Run Code Online (Sandbox Code Playgroud)

服务器

使用该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; }
}
Run Code Online (Sandbox Code Playgroud)

  • 在这种情况下,这不会以OP要求的形式发送“ application / x-www-form-urlencoded”数据。 (2认同)
  • 对我来说,当我从标头中“移除内容类型”并让浏览器自动执行此操作时,它就起作用了。谢谢! (2认同)
  • 如果你没有为 Fetch 设置“Content-type”,它会将其设置为“multipart/form-data”,这就是表单数据应该是的!然后你可以使用expressjs中的“multer”来轻松解析该数据格式。 (2认同)

gue*_*314 13

您可以设置bodyURLSearchParams带有作为参数传递的查询字符串的实例

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

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);
}
Run Code Online (Sandbox Code Playgroud)
<form>
  <input name="email" value="test@example.com">
  <input name="password" value="pw">
  <input type="submit">
</form>
Run Code Online (Sandbox Code Playgroud)

  • “ Reflect.apply(params.set,params,props)”是一种特别难以理解的说法,即“ params.set(props [0],props [1])”。 (2认同)

Kam*_*ski 13

使用FormDatafetch来抓取和发送数据

fetch(form.action, {method:'post', body: new FormData(form)});
Run Code Online (Sandbox Code Playgroud)

fetch(form.action, {method:'post', body: new FormData(form)});
Run Code Online (Sandbox Code Playgroud)
function send(e,form) {
  fetch(form.action, {method:'post', body: new FormData(form)});

  console.log('We send post asynchronously (AJAX)');
  e.preventDefault();
}
Run Code Online (Sandbox Code Playgroud)

  • 非常感谢,这就是我一直在寻找的东西,令人惊讶的是现在纯 JavaScript 可以如此简单。只要看看那个漂亮的 **1 liner** `fetch` 代码,它 `post` 了 `&lt;form&gt;` 数据,我仍然很惊讶我是如何找到这个的。再见 jQuery。 (2认同)

use*_*619 9

body:FormData ”有效,但有类型抱怨,“ FormData ”也设置多部分标题。为了使事情更简单,可以使用具有内联构造和手动设置标头的“ 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
    )
  }
Run Code Online (Sandbox Code Playgroud)


小智 6

要添加上面的好答案,您还可以避免在 HTML 中显式设置操作,并在 javascript 中使用事件处理程序,使用“this”作为表单来创建“FormData”对象

HTML 形式:

<form id="mainForm" class="" novalidate>
<!--Whatever here...-->
</form>
Run Code Online (Sandbox Code Playgroud)

在你的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
    });
});
Run Code Online (Sandbox Code Playgroud)


小智 6

\xe2\x80\x8d这些可以帮助您:

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

  • 您能否添加更多解释来说明您所做的更改使其变得更好 (2认同)

nic*_*ass 5

使用 fetch api,结果证明您不必包含标题“Content-type”:“multipart/form-data”。

所以以下工作:

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

fetch(yourUrlToPost, {
   method: "POST",
   body: formData
})
Run Code Online (Sandbox Code Playgroud)

请注意,使用 axios 我必须使用内容类型。

  • 我正在将文件和一些数据从 React 发送到 Flask,直到我删除 Content-type 后它才起作用。谢谢 :) (2认同)