XMLHttpRequest метод POST

XMLHttpRequest метод POST

Здравствуйте! В этом уроке  рассмотрим, что происходит при отправке данных  формы методом POST.

Во время отправки формы браузер собирает значения всех полей и делает из них строку, а после  составляет тело GET/POST-запроса для отсылки на сервер.

xmlhttprequest метод post отправки данных

А при отправке данных через XMLHttpRequest, это нужно делать самостоятельно, в JS-коде. Большинство проблем и вопросов  возникает как  раз  с кодировкой. Вот именно  об этих вопросах мы и  поговорим  в этой статье.

Кодировка urlencoded

Основной способ кодирования запросов – это urlencoded, то есть – стандартное кодирование URL.

Вот пример имеется  форма:

                     
<form action="/submit" method="GET"> <input name="name" value="Alex"> <input name="surname" value="Alexeev"> </form>

Здесь имеются 2 поля: name=Ivan и surname=Ivanov.

Браузер перечисляет такие пары «имя=значение» через символ амперсанда & и, так как используется метод GET, итоговый запрос выглядит как /submit?name=Alex&surname=Alexeev.

Все символы, кроме английских букв, цифр и — _ . ! ~ * ‘ ( ) заменяются на их цифровой код в UTF-8 со знаком %.

Например, пробел заменяется на %20, символ / на %2F, русские буквы кодируются двумя байтами в UTF-8, поэтому, к примеру, буква Ц заменится на %D0%A6.

Например:

                     
 <form action="/submit" method="GET"> <input name="name" value="Виктор"> <input name="surname" value="Цой"> </form>

Будет отправлена так: /submit?name=%D0%92%D0%B8%D0%BA%D1%82%D0%BE%D1%80&surname=%D0%A6%D0%BE%D0%B9.

в JavaScript имеется функция encodeURIComponent для получения такой кодировки «вручную»:

alert( encodeURIComponent(' ') ); 
// %20 alert( encodeURIComponent('/') ); 
// %2F alert( encodeURIComponent('В') ); 
// %D0%92 alert( encodeURIComponent('Виктор') ); 
// %D0%92%D0%B8%D0%BA%D1%82%D0%BE%D1%80

Эта кодировка используется в основном для метода GET, то есть для передачи параметра в строке запроса. По стандарту строка запроса не может содержать произвольные Unicode-символы.

GET-запрос

Формируя XMLHttpRequest, надо формировать запрос «руками», кодируя поля функцией encodeURIComponent.

Например, для посылки GET-запроса с параметрами name и surname, аналогично форме выше, их необходимо закодировать так:

// Передаём name и surname в параметрах запроса 
var xhr = new XMLHttpRequest(); 
var params = 'name=' + encodeURIComponent(name) + '&surname=' + encodeURIComponent(surname); 
xhr.open("GET", '/submit?' + params, true); 
xhr.onreadystatechange = ...; 
xhr.send();

Прочие заголовки

Браузер автоматически добавит к запросу нужные HTTP-заголовки, такие как Content-Length и Connection.

Читайте также  XMLHttpRequest и кросс-доменные запросы

По спецификации браузер запрещает их явную установку, как и некоторых других низкоуровневых HTTP-заголовков, которые могли бы ввести в заблуждение сервер относительно того, кто и сколько данных ему прислал, например Referer. Это делается в целях контроля правильности запроса и для безопасности.

Сообщаем про AJAX

Запрос, отправленный кодом выше через XMLHttpRequest, никак не отличается от обычной отправки формы. Сервер не в состоянии их отличить.
Поэтому в некоторых фреймворках, чтобы сказать серверу, что это AJAX, добавляют специальный заголовок:

xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");

POST с urlencoded

В методе POST параметры передаются не в URL, а в теле запроса. Оно указывается в вызове метода send(body).

В стандартных HTTP-формах для метода POST доступны 3 кодировки, которые задаются  через атрибут enctype:

  • application/x-www-form-urlencoded
  • multipart/form-data
  • text-plain

В зависимости от типа  enctype браузер кодирует данные соответствующим способом перед отправкой их  на сервер.

В случае с XMLHttpRequest мы, вообще говоря, и не обязаны использовать ни один из этих способов. Главное, чтобы сервер наш запрос понял. Но обычно проще всего выбрать какой-то из стандартных.

В частности, при POST обязателен заголовок Content-Type, содержащий кодировку. Это указание для сервера – как обрабатывать (раскодировать) пришедший запрос.

Для примера отправим давайте  запрос в кодировке application/x-www-form-urlencoded:

var xhr = new XMLHttpRequest(); 
var body = 'name=' + encodeURIComponent(name) + '&surname=' + encodeURIComponent(surname); 
xhr.open("POST", '/submit', true); xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); 
xhr.onreadystatechange = ...; 
xhr.send(body);

Только UTF-8

Всегда используется только кодировка UTF-8, независимо от языка и кодировки страницы.

Если сервер вдруг ожидает данные в другой кодировке, к примеру windows-1251, то их нужно будет перекодировать.

Кодировка multipart/form-data

Кодировка urlencoded за счёт замены символов на %код может сильно «раздуть» общий объём пересылаемых данных. Поэтому для пересылки файлов используется другая кодировка: multipart/form-data.

В этой кодировке поля пересылаются одно за другим, через строку-разделитель.

Читайте также  Основы объекта XMLHttpRequest

Чтобы использовать этот способ, нужно указать его в атрибуте enctype и метод должен быть POST:

                        
  <form action="/submit" method="POST" enctype="multipart/form-data"> 
<input name="name" value="Виктор"> <input name="surname" value="Цой"> 
</form>

То есть, поля передаются одно за другим, значения не кодируются, а чтобы было чётко понятно, какое значение где – поля разделены случайно сгенерированной строкой, которую называют «boundary» (англ. граница), в примере выше это RaNdOmDeLiMiTeR:

Сервер видит заголовок Content-Type: multipart/form-data, читает из него границу и раскодирует соответсвенно  поля формы.

Такой способ можно использовать в первую очередь при пересылке файлов, так перекодировка мегабайтов через urlencoded существенно загрузила бы браузер. Да и объём данных после неё сильно вырос бы.

Однако, никто не мешает вам использовать эту кодировку всегда для POST запросов. Для GET доступна только urlencoded.

POST с multipart/form-data

Сделать POST-запрос в кодировке multipart/form-data можно и через XMLHttpRequest.

Достаточно указать в заголовке Content-Type кодировку и границу, и далее сформировать тело запроса, удовлетворяющее требованиям кодировки.

Пример кода для того же запроса, что и раньше, теперь в кодировке multipart/form-data:

var data = { name: 'Виктор', surname: 'Цой' }; 
var boundary = String(Math.random()).slice(2); 
var boundaryMiddle = '--' + boundary + '\r\n'; 
var boundaryLast = '--' + boundary + '--\r\n' 
var body = ['\r\n']; for (var key in data) { 
// добавление поля 
body.push('Content-Disposition: form-data; name="' + key + '"\r\n\r\n' + data[key] + '\r\n'); 
} 
body = body.join(boundaryMiddle) + boundaryLast; 
// Тело запроса готово, отправляем 
var xhr = new XMLHttpRequest();
xhr.open('POST', '/submit', true); 
xhr.setRequestHeader('Content-Type', 'multipart/form-data; boundary=' + boundary); 
xhr.onreadystatechange = function() { 
if (this.readyState != 4) return; 
alert( this.responseText ); } 
xhr.send(body);

Тело запроса будет иметь вид, описанный выше, то есть поля через разделитель.

Отправка файла

Можно создать запрос, который сервер воспримет как загрузку файла.

Для добавления файла нужно использовать тот же код, что выше, модифицировав заголовки перед полем, которое является файлом, так:

Content-Disposition: form-data; name="myfile"; filename="pic.jpg" Content-Type: image/jpeg (пустая строка) содержимое файла

FormData

Современные браузеры, исключая IE9- (впрочем, есть полифилл), поддерживают встроенный объект FormData, который может кодировать формы для отправки на сервер.

Читайте также  COMET с XMLHttpRequest: непрерывные опросы

Это  бывает очень удобно. Например:

<form name="person"> 
<input name="name" value="Виктор"> 
<input name="surname" value="Цой"> 
</form> 
<script>
  // создать объект для формы 
var formData = new FormData(document.forms.person); 
// добавить к пересылке ещё пару ключ - значение 
formData.append("patronym", "Робертович"); // отослать 
var xhr = new XMLHttpRequest(); xhr.open("POST", "/url"); 
xhr.send(formData); </script>

Этот код отправит на сервер форму с полями name, surname и patronym.

Интерфейс:

  • Конструктор new FormData([form]) вызывается либо без аргументов, либо с DOM-элементом формы.
  • Метод formData.append(name, value) добавляет данные к форме.

Объект formData можно сразу отсылать, интеграция FormData с XMLHttpRequest встроена в браузер. Кодировка при этом будет multipart/form-data.

Другие кодировки

XMLHttpRequest сам по себе не ограничивает кодировку и формат пересылаемых данных.

Поэтому для обмена данными часто используется формат JSON:

var xhr = new XMLHttpRequest(); 
var json = JSON.stringify({ name: "Виктор", surname: "Цой" }); 
xhr.open("POST", '/submit', true) xhr.setRequestHeader('Content-type', 'application/json; charset=utf-8'); 
xhr.onreadystatechange = ...; 
// Отсылаем объект в формате JSON и с Content-Type application/json 
// Сервер должен уметь такой Content-Type принимать и раскодировать 
xhr.send(json);

Итоги

  • У форм есть 2 основные кодировки: application/x-www-form-urlencoded и multipart/form-data – для POST запросов, если она явно указана в enctype. Вторая кодировка обычно используется для передачи больших данных и только для тела запроса.
  • Для составления запроса в application/x-www-form-urlencoded есть функция encodeURIComponent.
  • Для отправки запроса в multipart/form-data –  есть объект FormData.
  • Для обмена данными клиент  ↔ сервер можно использовать и просто JSON, желательно с указанием кодировки в заголовке Content-Type.

В XMLHttpRequest вы можете использовать и другие HTTP-методы, как PUT, DELETE, TRACE.

Если вы нашли ошибку, пожалуйста, выделите фрагмент текста и нажмите Ctrl+Enter.

Поделиться

Об авторе

admin administrator

Сообщить об опечатке

Текст, который будет отправлен нашим редакторам: