Как анализировать multipart / form-data в облачных функциях firebase?

Я пытался опубликовать объект multipart / form-data с текстом и файлом изображения в одну из моих облачных функций, согласно документам здесь:

https://cloud.google.com/functions/docs/writing/http#multipart_data_and_file_uploads

Я сохранил свою облачную функцию почти так же, как и в примере, за исключением того, что заключил ее в ответ CORS. Однако кажется, что несмотря ни на что, события busboy 'field' и 'file' никогда не срабатывают, и когда я печатаю метод toString тела запроса, я получаю некоторые данные, прежде чем они перейдут в тарабарщину.

Возможно ли, что я что-то неправильно настраиваю при отправке FormData?

Вот код, содержащий мой XMLHttpRequest ():

var formData = new FormData(document.getElementById("ticketForm"));
return new Promise(function (resolve, reject) {
      var xmlhttp = new XMLHttpRequest();
      xmlhttp.open("POST", "https://us-central1-XXXXXXX.cloudfunctions.net/ticketFunction");
      var boundary = Math.random().toString().substr(8) + "--";
      xmlhttp.setRequestHeader('Content-Type', 'multipart/form-data;charset=utf-8; boundary=' + boundary);
      // xmlhttp.setRequestHeader('Content-Type', undefined);

      xmlhttp.onload = function () {
        if (this.status >= 200 && this.status < 300) {
          resolve(xmlhttp.response);
        } else {
          reject({
            status: this.status,
            statusText: xmlhttp.statusText
          });
        }
      };
      xmlhttp.onerror = function () {
        reject({
          status: this.status,
          statusText: xmlhttp.statusText
        });
      };
      xmlhttp.send(formData);
    });

Вот моя облачная функция:

exports.newTicketWithPhoto = functions.https.onRequest ((req, res) => {cors (req, res, () => {

if (req.method === 'POST') {

  const busboy = new Busboy({ headers: req.headers });
  const tmpdir = os.tmpdir();
  console.log("Length: " + req.headers['content-length']);
  console.log(req.body.toString());

  // This object will accumulate all the fields, keyed by their name
  const fields = {};

  // This object will accumulate all the uploaded files, keyed by their name.
  const uploads = {};

  // This code will process each non-file field in the form.
  busboy.on('field', (fieldname, val) => {
    // TODO(developer): Process submitted field values here
    console.log(`Processed field ${fieldname}: ${val}.`);
    fields[fieldname] = val;
  });

  busboy.on('error', function(err){
    console.log("Error: " + err);
  });

  // This code will process each file uploaded.
  busboy.on('file', (fieldname, file, filename) => {
    // Note: os.tmpdir() points to an in-memory file system on GCF
    // Thus, any files in it must fit in the instance's memory.
    console.log(`Processed file ${filename}`);
    const filepath = path.join(tmpdir, filename);
    uploads[fieldname] = filepath;
    file.pipe(fs.createWriteStream(filepath));
  });

  // This event will be triggered after all uploaded files are saved.
  busboy.on('finish', () => {
    // TODO(developer): Process uploaded files here
    console.log(fields);
    console.log("Uploads: " + JSON.stringify(uploads));
    for (const name in uploads) {
      console.log(name);
      const file = uploads[name];
      fs.unlinkSync(file);
    }
    res.send();
  });

  req.pipe(busboy);
} else {
  // Return a "method not allowed" error
  res.status(405).send("Something weird happened");
}

}) });

Я заметил следующее: при печати значения длины содержимого заголовка всегда кажется, что он возвращает значение undefined.

Когда я печатаю метод req.body.toString (), я получаю следующее:

 ------WebKitFormBoundaryeYZHuHsOLlohyekc
Content-Disposition: form-data; name="description"

testing description
------WebKitFormBoundaryeYZHuHsOLlohyekc
Content-Disposition: form-data; name="priority"

Low
------WebKitFormBoundaryeYZHuHsOLlohyekc
Content-Disposition: form-data; name="dueDate"

2018-07-27
------WebKitFormBoundaryeYZHuHsOLlohyekc
Content-Disposition: form-data; name="customer"

zavtra
------WebKitFormBoundaryeYZHuHsOLlohyekc
Content-Disposition: form-data; name="email"

[email protected]
------WebKitFormBoundarysseArmLvKhJY0TAm
Content-Disposition: form-data; name="photo"; filename="brighthabits1.png"
Content-Type: image/png

�PNG

IHRGB���@IDATx�}�ݴտ��I�$�V���*�EH ! �:(_7m)-ݻ�ί���{-dCaf��*�=!����N����ͽ�ږm�y�׶tt�OG�ʶ,6L���L*�ć[����V;�x�+[�c�/�0;@a�5��;��]]<x��\R�cqoG`rGƵ�t����O�y�J���"
����*�,�F,��.�ib�
                 ��I�.�SV�;��h�!v��~T�EY����(u\�4+&��I��9@~wP�`N��H�;�G"7.BI��h
                                                                               P��$R
                                                                                    �0pt,�[=��E��8����$^$��
"�,�,�4�>�Y�YY|�v3JSW��
                       )�q,���i>w��A��q\-
                                         �u���ՠ�hJW�oF������W7X��]��
                                                                    )#mx������&�њ�����iu���;D��ŗL��ޥh[F�8���D�^������IW��#��

                                �
                                 �
�TL�n���� {�l�`h����r   ��S>�[���&���_�%R8���W��mok�E����R���.]#@5������j���o���e����?Ӟ�u�Ţ�Y��5�N'�Nf��Թ#ߏ��E;�<�?^X��x�uπʭ�V??�� s�plzBǶ 

Я не уверен, что вызывает всю эту тарабарщину в конце, но это явно только тогда, когда я загружаю изображение. Когда в данных формы нет изображения, события busboy 'field' по-прежнему не срабатывают, что заставляет меня думать, что что-то все еще не анализируется правильно.

Это расстраивает, потому что в остальном мне кажется, что я в точности следую документации.


person Gabriel Garrett    schedule 23.07.2018    source источник
comment
Тарабарщина в конце - это фактическое содержимое файла. Если вы выполните для этого toString (), ожидается, что вы получите символы ASCII. Попробуйте открыть любой файл с помощью текстового редактора, и вы увидите то же самое.   -  person Edo Akse    schedule 21.08.2018
comment
Кроме того, есть ли на самом деле строки, напечатанные console.log('Processed field ${fieldname}: ${val}.');?   -  person Edo Akse    schedule 21.08.2018


Ответы (3)


Я слежу за этим репозиторием Загрузка изображений с помощью Busboy и очень хорошо работал с Firebase Cloud.

person Ythalo Rossy    schedule 29.06.2019

Официальные документы Google предлагают использовать пакет Busboy npm, как предполагает принятый ответ. Просто разместите их здесь, если они будут полезны другим:

https://cloud.google.com/functions/docs/writing/http#multipart_data

person DoubleA    schedule 22.08.2020

person    schedule
comment
Вы действительно проверили, что теперь это работает с Firebase? - person Leo; 06.05.2019
comment
Это сработало для меня с функциями Typescript! большое спасибо - person Mateo Tibaquira; 06.06.2019