Як опублікувати дані форми за допомогою api?


118

Мій код:

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

Я спробував опублікувати свою форму за допомогою інструменту для отримання інструментів, і тіло, яке вона надсилає, виглядає так:

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

Мені потрібно щось на зразок $ ("# форма"). Serialize () в jQuery (без використання jQuery) або спосіб декодування mulitpart / form-data в контролері. Дякую за відповіді.


Що з проблемою використання FormData?
гість271314

1
Я хочу опублікувати це як "email=test@example.com&password=pw". Це можливо?
Зак

1
"Я не знаю, чому число в кордоні змінюється щоразу, коли воно надсилається ..." - Ідентифікатор межі є лише випадковим ідентифікатором, він може бути будь-яким і не має ніякого значення сам по собі. Тож немає нічого поганого в тому, щоб вибрати там випадкове число (що зазвичай роблять клієнти).
ткнути

Відповіді:


149

Цитую MDN на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), ви також можете створити URLSearchParamsоб'єкт з FormDataоб'єкта:

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

Однак у браузерах все ще є деяка експериментальна підтримка, тому переконайтесь, що це правильно перевірити, перш ніж використовувати його.


18
Ви також можете використовувати об'єкт або просто FormDataв конструкторі безпосередньо замість циклу:new URLSearchParams(new FormData(formElement))
ченці, час

@ monk-time На момент написання цієї відповіді аргумент конструктора URLSearchParamsбув дуже новим і мав дуже обмежену підтримку.
ткнути

3
Вибачте, це була не скарга, а записка для всіх, хто читатиме це в майбутньому.
ченці

1
@Prasanth Ви можете самі вказати тип вмісту, але вам потрібно вибрати правильний . Простіше просто залишити його і fetchподбати про нього.
ткнути

1
@chovy URLSearchParamsвбудований у більшість сучасних браузерів як глобальний об'єкт, а також працює від Node.
ткнути

67

Клієнт

Не встановлюйте заголовок типу вмісту.

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

4
Хоча це працює, це не надсилає дані, оскільки application/x-www-form-urlencodedсаме про це вимагає ОП.
ткнути

5
Для мене це спрацювало, коли я ВІДНУТИсь Content-Type із заголовка і дозволити браузеру робити це автоматично. Дякую!
Кріс

Дякуємо @regnauld намагалися опрацювати це цілий день!
ak85

1
Якщо ви не встановите "Тип вмісту" для Fetch, він збирається встановити його як multipart/form-data, що має бути для даних форми! Тоді ви можете використовувати multerв expressjs легко проаналізувати цей формат даних.
kyw

23

Ви можете встановити 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>


2
Reflect.apply(params.set, params, props)є особливо нечитабельним способом висловлювання params.set(props[0], props[1]).
ткнути

@poke Reflect.apply(params.set, params, props)читається з точки зору.
гість271314

Це здається єдиною робочою відповіддю тут: / дякую! :)
OZZIE

0

Використання FormDataі fetchдля захоплення і відправки даних


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
Відповіді лише на код можна, як правило, покращити, додавши пояснення як і чому вони працюють. Додаючи відповідь на дворічне запитання з наявними відповідями, важливо вказати, який новий аспект питання стосується вашої відповіді.
Джейсон Аллер
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.