JavaScript. Подробное руководство, 6-е издание, стр. 283

<b>// выбранный файл по указанному URL-адресу &quot;uploadto&quot;. Ответ сервера игнорируется. </b>

<b>whenReady(function() { // Вызвать эту функцию после загрузки документа</b>

<b>  var elts = document.getElementsByTagName(&quot;input”); // Все элементы input</b>

<b>  for(var і = 0; і &lt; elts.length; i++) { // Обойти в цикле</b>

<b>    var input = elts[i];</b>

<b>    if (input.type !== ’'file&quot;) continue; // Пропустить все, кроме</b>

<b>                                          // элементов выгрузки файлов</b>

<b>    var url = input.getAttribute(&quot;data-uploadto&quot;); // Адрес выгрузки</b>

<b>    if (!url) continue; // Пропустить элементы без url</b>

<b>    input.addEventListener(&quot;change&quot;, function() { // При выборе файла</b>

<b>      var file = this.files[0]; // Предполагается выбор единственного файла</b>

<b>      if (!file) return; // Если файл не выбран, ничего не делать</b>

<b>      var xhr = new XMLHttpRequest(); // Создать новый запрос</b>

<b>      xhr.open(&quot;POST&quot;, url); // Методом POST на указанный URL</b>

<b>      xhr.send(file); // Отправить файл в теле запроса</b>

<b>    }, false);</b>

<b>  }</b>

<b>});</b>

Как будет показано в разделе 22.6, тип

<b>File</b>
является подтипом более общего типа
<b>Blob</b>
. Спецификация «ХНН2» позволяет передавать методу
<b>send()</b>
произвольные объекты
<b>Blob</b>
. Свойство
<b>type</b>
объекта
<b>Blob</b>
в этом случае будет использоваться для установки заголовка «Content-Type», если он не будет определен явно. Если потребуется выгрузить двоичные данные, сгенерированные клиентским сценарием, можно воспользоваться приемами преобразования данных в объект
<b>Blob</b>
, демонстрируемыми в разделах 22.5 и 22.6.3, и передавать в виде тела запроса этот объект.

18.1.3.5. Запросы с данными в формате multipart/form-data

Когда наряду с другими элементами HTML-формы включают элементы выгрузки файлов, броузер не может использовать обычный способ представления данных форм и должен отправлять формы, используя специальное значение «multipart/form-data» в заголовке «Content-Type». Этот формат связан с использованием длинных «граничных» строк, делящих тело запроса на несколько частей. Для текстовых данных можно вручную создать тело «multipart/form-data» запроса, но это довольно сложно.

Спецификация «ХНН2» определяет новый прикладной интерфейс

<b>FormData</b>
, упрощающий создание тела запроса, состоящего из нескольких частей. Сначала с помощью конструктора
<b>FormData()</b>
создается объект
<b>FormData</b>
, а затем вызовом метода
<b>append()</b>
этого объекта в него добавляются отдельные «части» (которые могут быть строками или объектами
<b>File</b>
и
<b>Blob</b>
). В заключение объект
<b>FormData</b>
передается методу
<b>send().</b>
Метод
<b>send()</b>
определит соответствующую строку, обозначающую границу, и установит заголовок «Content-Type» запроса. Пример 18.10 демонстрирует использование объекта
<b>FormData</b>
, с которым мы еще встретимся в примере 18.11.

Пример 18.10. Отправка запроса с данными в формате multipart/form-data

<b>function postFormData(url, data, callback) {</b>

<b>  if (typeof FormData === &quot;undefined&quot;)</b>

<b>    throw new Error(&quot;Объект FormData не реализован&quot;);</b>

<b>  var request = new XMLHttpRequest(); // Новый HTTP-запрос</b>

<b>  request.open(&quot;POST&quot;, url); // Методом POST на указанный URL</b>

<b>  request.onreadystatechange = function() { // Простой обработчик,</b>

<b>    if (request.readyState === 4 &amp;&amp; callback) // При получении ответа</b>

<b>      callback(request); // вызвать указанную функц.</b>

<b>  };</b>

<b>  var formdata = new FormData();</b>

<b>  for(var name in data) {</b>

<b>    if (!data.hasOwnProperty(name)) continue; // Пропустить унасл. св-ва</b>

<b>    var value = data[name];</b>

<b>    if (typeof value === &quot;function”) continue; // Пропустить методы</b>

<b>    // Каждое свойство станет отдельной &quot;частью&quot; тела запроса.</b>

<b>    // Допускается использовать объекты File</b>

<b>    formdata.append(name, value); // Добавить имя/значение,</b>

<b>  } // как одну часть</b>

<b>  // Отправить пары имя/значение в теле запроса multipart/form-data. Каждая пара -</b>

<b>  // это одна часть тела запроса. Обратите внимание, что метод send автоматически</b>

<b>  // устанавливает заголовок Content-Type, когда ему передается объект FormData</b>

<b>  request.send(formdata);</b>

<b>}</b>

18.1.4. События, возникающие в ходе выполнения НТТР-запроса

В примерах выше для определения момента завершения HTTP-запроса использовалось событие «readystatechange». Проект спецификации «ХНН2» определяет более удобный набор событий, уже реализованный в Firefox, Chrome и Safari. В этой новой модели событий объект

<b>XMLHttpRequest</b>
генерирует различные типы событий на разных этапах выполнения запроса, благодаря чему отпадает необходимость проверять значение свойства
<b>readyState</b>
.