Xpoint
   [напомнить пароль]

Отправка multipart/formdata с XMLHttpRequest

2004-07-28 18:31:34 [обр] Kirill [досье]

Отправление файла с помощью XMLHttpRequest ниже изучил, бинарные файлы отправляются без проблем. Вопрос в том, каким образом все-таки имитировать отправку формы. Попытка указать Content-type как multipart/formdata и добавить заголовок Content-Disposition: form-data; name="file"; filename="image.gif" не помогают. Как я понимаю, нужно сформировать соответствующий текст в stringStream.setData("\r", 2), но опять же вставка туда текста, скопированного из тела POST-запроса после отправки файла браузером, не помогают. Код:

var file = Components.classes["@mozilla.org/file/local;1"]
                     .createInstance(Components.interfaces.nsILocalFile);
file.initWithPath(filepath);

var xmlhttpUpload = new XMLHttpRequest();
xmlhttpUpload.open("POST", "http://localhost/UPLOAD.html", false);
xmlhttpUpload.setRequestHeader("Content-Length", file.fileSize);
xmlhttpUpload.setRequestHeader("Content-Type", "multipart/formdata");

var multiplexStream = Components.classes["@mozilla.org/io/multiplex-input-stream;1"]
                                .createInstance(Components.interfaces.nsIMultiplexInputStream);
var stringStream = Components.classes["@mozilla.org/io/string-input-stream;1"]
                             .createInstance(Components.interfaces.nsIStringInputStream);
var data = '-----------------------------265001916915724';
data += 'Content-Disposition: form-data; name="uploaderfile"; filename="image.gif"';
date += 'Content-Type: image/gif\r';
stringStream.setData("\r" + data, 2);

var fileStream = Components.classes["@mozilla.org/network/file-input-stream;1"]
                           .createInstance(Components.interfaces.nsIFileInputStream);
fileStream.init(file, 0x01, 0444, null);
multiplexStream.appendStream(stringStream);
multiplexStream.appendStream(fileStream);

var bufferedStream = Components.classes["@mozilla.org/network/buffered-input-stream;1"]
                               .createInstance(Components.interfaces.nsIBufferedInputStream);
bufferedStream.init(multiplexStream, file.fileSize);
xmlhttpUpload.send(bufferedStream);

Доставляет на сервер по прежнему только файл без определения полей формы.
Подскажите, плиз, как правильно сформировать заголовки и определить имя поля формы с файлом. Благодарю за помощь.

спустя 1 день 18 часов [обр] Владимир Палант [досье]

Посмотрите исходники любого email для примера multipart-сообщений. В частности вам нужно установить Content-Type как multipart/formdata; boundary=-----------------------------265001916915724 и после файла еще послать завершающую строку:

-----------------------------265001916915724--

В качестве boundary может выступать и любая другая строка. В остальном ваш код вроде бы все правильно делает.

спустя 1 час 32 минуты [обр] Kirill [досье]

Владимир, спасибо за совет. Я установил Content-type с указанием boundary, но проблема сохранилась. В body POST-запроса по-прежнему попадает только содержимое файла без boundary и соответствующих заголовков этой части запроса.
Должно быть (при сохранении тела запроса при отвравке браузером):

-----------------------------0000000000000000
Content-Disposition: form-data; name="file"; filename="image.gif"
Content-Type: image/gif

GIF89etc

а при отправке из метода получаю только GIF89etc
Все заголовки приходят правильными, как и были заданы :( Такое впечатление, что конструкция stringStream.setData("\r" + data, 2); тихо игнорируется.

спустя 1 час 55 минут [обр] Владимир Палант [досье]
А, ну да... Второй параметр там ведь длина данных. Ну и с переводами строки вы напутали. То есть писать вы должны:
var data = '-----------------------------265001916915724\r';
data += 'Content-Disposition: form-data; name="uploaderfile"; filename="image.gif"\r';
date += 'Content-Type: image/gif\r\r';
stringStream.setData(data, data.length);
спустя 6 дней [обр] Kirill [досье]
Владимир, благодарю за помощь. Удалось добиться соответствия тела запроса при XMLHttpRequest тому, что приходит из html-формы. При этом доступ к полю формы с файлом все равно невозможен :( но это, видимо, уже проблемы серверного интерпретатора. Буду разбираться по приезде из отпуска, о результатх отчитаюсь :) На самом деле просто удивительно, что нет информации по теме, неужели никому не требуется имитация отправки формы ? Что для MSIE такая ситуация, что для Mozilla. Никаких FAQ по проблеме нету ...
спустя 3 месяца 10 дней [обр] Kirill [досье]

Маленькое добавление спустя время. Сейчас я приложения запускаю под Xul Runner, а не под обычной Мозиллой. Так если кто столкнется - там не требуется создавать stringStream и добавлять \r. Работающий под xulrunner код:

this.uploadFile = function(source, target, filter) { // binary uploan - no form fields
  var serverUrl = "http://" + SF.Config.session + wsupload + "path=" + target;
  var dFile = getFileOnPath(source||getFileOnPicker(filter));
  if (dFile) {
    var fileSizer = dFile.fileSize;
    var fileStream = FileInputStream(); 
    fileStream.init(dFile, 0x01, 0444, null);

    var bufferedStream = BufferedInputStream(); 
    bufferedStream.init(fileStream, fileSizer);

    var xmlhttpUpload = new XMLHttpRequest();
    xmlhttpUpload.open("POST", serverUrl, false);
    xmlhttpUpload.setRequestHeader("Content-length", fileSizer);
    xmlhttpUpload.setRequestHeader("Content-type", types_map[getFileExt(source)]);
    xmlhttpUpload.send(bufferedStream);
    try {
      var resp = xmlhttpUpload.responseXML.documentElement;
      if (resp.tagName == "methodResponse" && resp.getAttribute("status"))
        return true;
      else {
        alert("Error upload file, server response ststus " + xmlhttpUpload.status);
        return false;
      }
    } catch(e) {
      alert(e + "Impossible, is not catalog or dir chmod is not write privilegies ?URL: " + serverUrl);
      return false; 
    }
  } else {
    alert('File ' + source + ' not found or empty!');
    return false;
  }
}

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

Powered by POEM™ Engine Copyright © 2002-2005