С помощью объекта FormData можно отправить данные формы из кода JavaScript на сервер через Ajax. Рассмотрим прстейший пример. В качестве сервера, как и в прошлых статьях, будем использовать Node.js.
Сначала создадим файл app.js, который будет представлять сервер. Определим в нем самую простейшую логику:
const http = require("http");
const fs = require("fs");
http.createServer(async (request, response) => {
if(request.url == "/user"){
let body = ""; // буфер для получаемых данных
// получаем данные из запроса в буфер
for await (const chunk of request) {
body += chunk;
}
// для параметра name
let userName = "";
// для параметра age
let userAge = 0;
// регулярное выражения для поиска названия и значения поля формы
const exp = /Content-Disposition: form-data; name="([^\"]+)\"\r\n\r\n(\w*)/g;
let formElement;
while ((formElement = exp.exec(body))){
paramName = formElement[1]; // получаем имя элемента формы
paramValue = formElement[2]; // получаем значение элемента формы
console.log(paramName, ":", paramValue); // выводим на консоль
if(paramName === "name") userName = paramValue;
if(paramName === "age") userAge = paramValue;
}
response.end(`Your name: ${userName} Your Age: ${userAge}`);
}
else{
fs.readFile("index.html", (_, data) => response.end(data));
}
}).listen(3000, ()=>console.log("Сервер запущен по адресу http://localhost:3000"));
Вкратце пробежимся по коду. Сначала подключаются пакеты с функциональностью, которую мы собираемся использовать:
const http = require("http"); // для обработки входящих запросов
const fs = require("fs"); // для чтения файлов с жесткого диска
Для создания сервера применяется функция http.createServer(). В эту функцию передается функция-обработчик, которая вызывается каждый раз, когда к серверу приходит запрос.
Эта функция имеет два параметра: request (содержит данные запроса) и response (управляет отправкой ответа).
В функции-обработчике с помощью свойства request.url мы можем получить путь к ресурсу, к которому пришел запрос. Здесь мы предполагаем, что клиент
будет отправлять форму по адресу "/user". И в начале обрабатывает запрос по этому адресу:
if(request.url == "/user"){
Для получения значений отправленной формы считываем тело запроса в переменную body:
let body = ""; // буфер для получаемых данных
// получаем данные из запроса в буфер
for await (const chunk of request) {
body += chunk;
}
Чтобы было представление, что будет содержать body после считывания тела запроса. Допустим, на форме два поля, которые называются name и age. В этом случае тело запроса будет выглядеть примерно следующим образом:
------WebKitFormBoundarya9nLzvDVEN5gPA5Q Content-Disposition: form-data; name="name" Tom ------WebKitFormBoundarya9nLzvDVEN5gPA5Q Content-Disposition: form-data; name="age" 39 ------WebKitFormBoundarya9nLzvDVEN5gPA5Q--
Здесь мы видим маркер границы ------WebKitFormBoundarya9nLzvDVEN5gPA5Q, который определяет начало и конец тела запроса, а также отделяет значения отдельных полей формы. (Значение
маркера границы может меняться). Для каждого поля формы определяется выражение Content-Disposition: form-data;. Затем с помощью атрибута name указано имя поля формы.
Затем через одну строку указано значение соответствующего поля. То есть в примере выше у нас два поля формы: поле "name" со значением "Tom" и поле "age" со
значением 39.
Теперь наша задача извлечь названия и значения полей формы. Для этого используем регулярное выражение
const exp = /Content-Disposition: form-data; name="([^\"]+)\"\r\n\r\n(\w*)/g;
Далее проходим по телу запроса регулярным выражением и извлекаем все элементы формы и их значения:
while ((formElement = exp.exec(body))){
paramName = formElement[1]; // получаем имя элемента формы
paramValue = formElement[2]; // получаем значение элемента формы
if(paramName === "name") userName = paramValue;
if(paramName === "age") userAge = paramValue;
}
Стоит отметить, что это естественно неполноценный парсинг, который не учитывает многие моменты (отправку массивов, файлов и т.д.) и приведен только для демонстраниции ajax-запросов.
После получения данных запроса отправляем в ответ клиенту некоторое сообщение:
response.end(`Your name: ${userName} Your Age: ${userAge}`);
В конце с помощью функции listen() запускаем веб-сервер на 3000 порту. То есть сервер будет запускаться по адресу http://localhost:3000/
Теперь определим файл index.html, который находится в одной папке с файлом сервера app.js и который будет представлять код клиента:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>METANIT.COM</title>
</head>
<body>
<script>
// данные для отправки
const formData = new FormData();
formData.append("name", "Tom");
formData.append("age", 39);
const xhr = new XMLHttpRequest();
xhr.onload = () => {
if (xhr.status == 200) {
console.log(xhr.responseText);
} else {
console.log("Server response: ", xhr.statusText);
}
};
xhr.open("POST", "user", true);
xhr.send(formData);
</script>
</body>
</html>
Здесь данные формы определяются вручную в виде объекта FormData. После создания объекта FormData с помощью метода add() в него можно
добавлять отдельные свойства и их значения. Затем для отправки на сервер объект FormData в качестве аргумента методу send().
В качестве метода HTTP устанавливается метод POST.
В обработчике onload выводим полученное от сервера сообщение на консоль.
В конце перейдем в консоли к папке сервера с помощью команды cd и запустим сервер с помощью команды node server.js
C:\app>node server.js Сервер запущен по адресу http://localhost:3000
После запуска сервера мы можем перейти в браузере по адресу http://localhost:3000, нам отобразится страница, в javascript-коде которой будет выполняться POST-запрос по адресу "/user". Код javascript получит ответ от сервера и выведет его на консоль:
В примере выше данные формы определяются вручную. Но аналогичным образом можно отправлять и данные форм, которые определены в коде html. Например, изменим код страницы index.html следующим образом:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>METANIT.COM</title>
</head>
<body>
<form id="myForm" method="post" action="/user">
<p>
<label>User Name:</label><br>
<input name="name" />
</p>
<p>
<label>User Age:</label><br>
<input name="age" />
</p>
<input type="submit" value="Send" />
</form>
<script>
// данные для отправки
const myForm = document.getElementById("myForm");
myForm.addEventListener("submit", (e)=>{
e.preventDefault();
const formData = new FormData(myForm);
const xhr = new XMLHttpRequest();
xhr.onload = () => {
if (xhr.status == 200) {
console.log(xhr.responseText);
}
};
xhr.open("POST", "user", true);
xhr.send(formData);
});
</script>
</body>
</html>
Здесь в коде формы определена форма с двумя полями ввода для отправки на сервер. Причем эти поля также имеют названия name и age. В коде JavaScript перехватываем отправку формы, из формы получаем объект FormData и отправляем его на сервер.