Làm cách nào để đăng dữ liệu biểu mẫu với api tìm nạp?


117

Mã của tôi:

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

Tôi đã cố gắng đăng biểu mẫu của mình bằng cách sử dụng api tìm nạp và nội dung mà nó gửi đi như sau:

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

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

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

(Tôi không biết tại sao số trong ranh giới bị thay đổi mỗi khi nó gửi ...)

Tôi muốn nó gửi dữ liệu có "Content-Type": "application / x-www-form-urlencoded", tôi phải làm gì? Hoặc nếu tôi phải xử lý nó, làm cách nào để giải mã dữ liệu trong bộ điều khiển của tôi?


Trả lời câu hỏi của tôi cho ai, tôi biết tôi có thể làm điều đó với:

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

Những gì tôi muốn là một cái gì đó như $ ("# form"). Serialize () trong jQuery (w / o sử dụng jQuery) hoặc cách giải mã mulitpart / form-data trong controller. Cảm ơn câu trả lời của bạn mặc dù.


Vấn đề với việc sử dụng là FormDatagì?
271314

1
Tôi muốn đăng nó dưới dạng "email=test@example.com&password=pw". Nó có khả thi không?
Zack

1
“Tôi không biết tại sao số trong ranh giới lại bị thay đổi mỗi khi nó gửi đi…” - Số nhận dạng ranh giới chỉ là một số nhận dạng ngẫu nhiên, nó có thể là bất kỳ thứ gì và không có bất kỳ ý nghĩa nào. Vì vậy, không có gì sai khi chọn một số ngẫu nhiên ở đó (đó là những gì khách hàng thường làm).
poke

Câu trả lời:


149

Để trích dẫn MDN trênFormData (nhấn mạnh của tôi):

Các FormDatagiao diện cung cấp một cách dễ dàng xây dựng một tập hợp các cặp khóa / giá trị đại diện cho các lĩnh vực hình thức và giá trị của họ, có thể sau đó được dễ dàng gửi bằng cách sử dụng XMLHttpRequest.send()phương pháp. Nó sử dụng cùng một định dạng mà một biểu mẫu sẽ sử dụng nếu loại mã hóa được đặt thành"multipart/form-data" .

Vì vậy, khi sử dụng FormData bạn đang tự nhốt mình vào multipart/form-data. Không có cách nào để gửi một FormDatađối tượng dưới dạng phần thân và không gửi dữ liệu ở multipart/form-datađịnh dạng.

Nếu bạn muốn gửi dữ liệu vì application/x-www-form-urlencodedbạn sẽ phải chỉ định phần nội dung là một chuỗi mã hóa URL hoặc chuyển một URLSearchParamsđối tượng. Rất tiếc, cái sau không thể được khởi tạo trực tiếp từ một formphần tử. Nếu bạn không muốn tự mình lặp lại các thành phần biểu mẫu của mình (bạn có thể làm điều này bằng cách sử dụng HTMLFormElement.elements), bạn cũng có thể tạo một URLSearchParamsđối tượng từ một FormDatađối tượng:

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

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

Lưu ý rằng bạn không cần phải tự chỉ định Content-Typetiêu đề.


Theo ghi nhận của tu sĩ thời gian trong các nhận xét, bạn cũng có thể tạo URLSearchParamsvà chuyển FormDatađối tượng trực tiếp, thay vì nối các giá trị trong một vòng lặp:

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

Tuy nhiên, điều này vẫn có một số hỗ trợ thử nghiệm trong các trình duyệt, vì vậy hãy đảm bảo kiểm tra điều này đúng cách trước khi bạn sử dụng.


18
Bạn cũng có thể sử dụng một đối tượng hay chỉ FormDatatrong các nhà xây dựng trực tiếp thay vì một vòng:new URLSearchParams(new FormData(formElement))
sư thời gian

@ sư-time Tại thời điểm viết câu trả lời rằng, đối số nhà xây dựng để URLSearchParamsrất mới và đã rất hạn chế hỗ trợ.
poke

3
xin lỗi, đó không phải là một lời phàn nàn, chỉ là một lưu ý cho những ai sẽ đọc nó trong tương lai.
thời gian nhà sư,

1
@Prasanth Bạn có thể tự chỉ định loại nội dung một cách rõ ràng, nhưng bạn phải chọn đúng . Sẽ dễ dàng hơn nếu bạn chỉ cần để nó đi và có người fetchchăm sóc nó cho bạn.
poke

1
@chovy URLSearchParamsđược tích hợp vào hầu hết các trình duyệt hiện đại như một đối tượng toàn cầu và cũng hoạt động từ Node.
poke

67

Khách hàng

Không đặt tiêu đề loại nội dung.

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

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

Người phục vụ

Sử dụng FromFormthuộc tính để chỉ định rằng nguồn liên kết là dữ liệu biểu mẫu.

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

4
Trong khi điều này hoạt động, điều này không gửi dữ liệu như application/x-www-form-urlencodednhững gì OP đang yêu cầu.
poke

5
Đối với tôi, nó hoạt động khi tôi XÓA Content-Type khỏi tiêu đề và để trình duyệt tự động làm điều đó. Cảm ơn!
Chris

Cảm ơn @regnauld đã cố gắng giải quyết vấn đề này cả ngày!
ak85

1
Nếu bạn không đặt 'Content-type' cho Tìm nạp, nó sẽ đặt nó thành multipart/form-data, đó là những gì nó nên dành cho dữ liệu biểu mẫu! Sau đó, bạn có thể sử dụng multertrong expressj để phân tích cú pháp định dạng dữ liệu đó một cách dễ dàng.
kyw 23/09/19

23

Bạn có thể đặt bodythành một phiên bản của URLSearchParamsvới chuỗi truy vấn được truyền dưới dạng đối số

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>


2
Reflect.apply(params.set, params, props)là một cách nói đặc biệt khó đọc params.set(props[0], props[1]).
poke

@poke Reflect.apply(params.set, params, props)có thể đọc được từ góc độ ở đây.
271314

Đây dường như là câu trả lời làm việc duy nhất ở đây: / cảm ơn bạn! :)
OZZIE

0

Sử dụng FormDatafetchđể lấy và gửi dữ liệu


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

7
Nói chung, câu trả lời chỉ có mã có thể được cải thiện bằng cách thêm một số giải thích về cách thức và lý do tại sao chúng hoạt động. Khi thêm câu trả lời cho một câu hỏi hai năm tuổi với các câu trả lời hiện có, điều quan trọng là phải chỉ ra khía cạnh mới của câu hỏi mà câu trả lời của bạn đề cập đến.
Jason Aller
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.