ChatGPT解决这个技术问题 Extra ChatGPT

如何使用 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",
}

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

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

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

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

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

我希望它使用“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",
}

我想要的是 jQuery 中的 $("#form").serialize() (不使用 jQuery)或在控制器中解码 mulitpart/form-data 的方式。不过感谢您的回答。

使用 FormData 有什么问题?
我想将其发布为“email=test@example.com&password=pw”。可能吗?
“我不知道为什么每次发送都会改变边界中的数字......” - 边界标识符只是一个随机标识符,它可以是任何东西,它本身没有任何意义。所以在那里选择一个随机数并没有错(这是客户通常所做的)。

p
poke

引用 MDN on FormData(强调我的):

FormData 接口提供了一种方法来轻松构造一组表示表单字段及其值的键/值对,然后可以使用 XMLHttpRequest.send() 方法轻松发送。如果编码类型设置为“multipart/form-data”,它使用与表单相同的格式。

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

如果要将数据作为 application/x-www-form-urlencoded 发送,则必须将正文指定为 URL 编码字符串,或传递 URLSearchParams 对象。遗憾的是,后者不能直接从 form 元素初始化。如果您不想自己遍历表单元素(可以使用 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(…);

请注意,您不需要自己指定 Content-Type 标头。

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

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

不过,这在浏览器中仍有一些实验性支持,因此请确保在使用之前对其进行正确测试。


您也可以在构造函数中直接使用对象或仅使用 FormData 而不是循环:new URLSearchParams(new FormData(formElement))
@monk-time 在撰写该答案时,URLSearchParams 的构造函数参数是非常 新的,并且支持非常有限。
抱歉,这不是投诉,只是给以后会阅读此内容的每个人的说明。
@Prasanth您可以自己明确指定内容类型,但您必须选择 正确 一个。将其关闭并让 fetch 为您处理会更容易。
如果您需要发布 FormData,则无需使用 URLSearchParams fetch(url, { method: 'post', body: new FormData(form_element), })
r
regnauld

客户

不要设置内容类型标头。

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

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

服务器

使用 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; }
}

虽然这可行,但这不会将数据作为 OP 要求的 application/x-www-form-urlencoded 发送。
对我来说,当我从标题中 REMOVED Content-Type 并让浏览器自动执行时,它就起作用了。谢谢!
如果您没有为 Fetch 设置 'Content-type',它会将其设置为 multipart/form-data,这就是表单数据应该是的!然后您可以在 expressjs 中使用 multer 轻松解析该数据格式。
这对我有用。我使用 Laravel 8 (Sanctum) 作为后端。
K
Kamil Kiełczewski

使用 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('我们异步发送帖子 (AJAX)'); e.preventDefault(); }

在 chrome 控制台上查看>“提交”之前/之后的网络


非常感谢,这就是我一直在寻找的东西,令人惊讶的是,现在纯 JavaScript 是多么容易。看看那个漂亮的 1 liner fetch 代码 post <form> 数据,我仍然很惊讶我是如何找到这个的。再见 jQuery。
这里根本不重要,但隐藏输入的名称有错字。对于想知道为什么会出现该输入的任何人,csrf 代表跨站点请求伪造。
选项 method: 'post' 无效,因为浏览器将使用传递给 FormDataform 的方法属性。即使在 form 中未定义方法属性,浏览器也会回退到默认的 GET 方法。
@MarcoMannes 如果您从上面代码段中的 fetch 参数中删除 mehtod:'post',您将获得 Request with GET/HEAD method cannot have body. 异常。如果您从上述代码段中的 html 中删除 method="POST",则 method:'post'(在 fetch 参数中)将生效 - 并且浏览器将发送 POST - 我通过修改此代码段并使用 chrome>network 选项卡来检查这一点(所以实际上我们可以删除这是来自 html ......但我会离开它)
form.action 是端点 url 吗?
C
Community

您可以将 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();控制台日志(响应); }


Reflect.apply(params.set, params, props) 是一种特别难以理解的方式来表达 params.set(props[0], props[1])
@poke Reflect.apply(params.set, params, props) 从这里的角度是可读的。
这似乎是这里唯一可行的答案:/谢谢! :)
如果我通过 body:new URLSearchParams("img="+my5MBimage) 发送一个 5MB 的图像文件怎么办?
@PYK在这种情况下,您不能使用 application/x-www-form-urlencoded 但 multipart/form-data: application/x-www-form-urlencoded or multipart/form-data?
n
nicolass

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

所以以下工作:

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

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

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


我正在将一个文件和一些数据从 React 发送到 Flask,直到我删除了 Content-type,它才起作用。谢谢 :)
P
Pablo Fernandez

👨‍💻这些可以帮助你:

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

您能否添加更多解释来说明您所做的更改使其变得更好
no-cors 和 Content-Type 标头几乎肯定是错误的。
m
magicsign

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

html格式:

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

在你的 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
    });
});

r
run_the_race

@KamilKiełczewski 如果您对表单数据格式采用表单多部分样式没问题,那么答案非常好,但是如果您需要以查询参数样式提交的表单:

如果您想以使用简单 GET 提交的方式生成查询参数,也可以将 FormData 直接传递给 URLSearchParams 构造函数。

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

u
user16547619

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

F
Fansy

MDN 上有关于浏览器将自动处理 Content-Type 的说明。

[如果字典中没有设置,请求也会自动设置 Content-Type 头。](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch#body)

所以我们在发送 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);
});

如果在标题中设置 content-type。浏览器不会尝试在请求负载中拆分表单数据。

我使用 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);
    });

s
soufiane ELAMMARI

要使用 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"
  });
 }

通常可以通过添加一些关于它们如何工作以及为什么工作的解释来改进仅代码的答案。在使用现有答案添加一个两年前的问题的答案时,重要的是要指出您的答案所针对的问题的新方面。