Подтвердить что ты не робот

Как отправить multipart/form-data с помощью супергагента node.js

Я пытаюсь отправить тип содержимого в моем суперагентном почтовом запросе на multipart/form-data.

var myagent = superagent.agent();

myagent
  .post('http://localhost/endpoint')
  .set('api_key', apikey)
  .set('Content-Type', 'multipart/form-data')
  .send(fields)
  .end(function(error, response){
    if(error) { 
       console.log("Error: " + error);
    }
  });

Ошибка, которую я получаю:   TypeError: Аргумент должен быть строкой

Если я удалю:

.set('Content-Type', 'multipart/form-data')

Я не получаю никаких ошибок, но мой задний конец получает запрос как тип контента: application/json

Как заставить тип контента быть multipart/form-data, чтобы я мог получить доступ к req.files()?

4b9b3361

Ответ 2

Неясно, что находится в переменной fields, которую вы отправляете, но вот некоторая информация, которая может помочь вам определить, где находится ваша проблема.

Для начала, если вы на самом деле пытаетесь построить многочастный запрос, это официальная документация для этого: http://visionmedia.github.com/superagent/#multipart-requests

как для ошибки, которую вы получили...

Причина в том, что в процессе подготовки запроса SuperAgent проверяет данные, которые нужно отправить, чтобы узнать, является ли это строкой. Если это не так, он пытается сериализовать данные на основе значения "Content-Type" , как показано ниже:

exports.serialize = {
  'application/x-www-form-urlencoded': qs.stringify,
  'application/json': JSON.stringify
};

который используется здесь:

// body
if ('HEAD' != method && !req._headerSent) {
  // serialize stuff
  if ('string' != typeof data) {
    var serialize = exports.serialize[req.getHeader('Content-Type')];
    if (serialize) data = serialize(data);
  }

  // content-length
  if (data && !req.getHeader('Content-Length')) {
    this.set('Content-Length', Buffer.byteLength(data));
  }
}

это означает, что для установки формы "Content-Type" вручную вы должны использовать

.set('Content-Type', 'application/x-www-form-urlencoded')

или

.type('form') как risyasin, упомянутый

любой другой "Content-Type" не будет сериализован, а Buffer.byteLength(data) впоследствии выбросит исключение TypeError: Argument must be a string, если значение вашей переменной fields не является строкой.

Ответ 3

В 2017 сделайте это так.

Во-первых, вы НЕ упоминаете одно из следующих:

.set('Content-Type', 'multipart/form-data')

ИЛИ

.type('form')

Во-вторых, вы НЕ используете .send, вы используете .field(name, value).

Пример

Предположим, вы хотите отправить запрос данных формы со следующим:

  • два текстовых поля: name и phone
  • один файл: photo

Итак, ваш запрос будет примерно таким:

superagent
  .post( 'https://example.com/api/foo.bar' )
  .set('Authorization', '...')
  .accept('application/json')
  .field('name', 'My name')
  .field('phone', 'My phone')
  .attach('photo', 'path/to/photo.gif')

  .then((result) => {
    // process the result here
  })
  .catch((err) => {
    throw err;
  });

И, допустим, вы хотели отправить JSON в качестве значения одного из ваших полей, тогда вы сделаете это.

superagent
  .post( 'https://example.com/api/dog.crow' )
  .accept('application/json')

  .field('data', JSON.stringify({ name: 'value' })   )

  .then( ... )
  .catch( ... )

Ответ 4

просто потерял много лет своей жизни. Я не мог заставить его работать, как хотелось бы богам программирования, но я придумал рабочий хак (я хотел запустить запрос AJAX каждый раз, когда изменился входной файл):

<input type="file" onchange="handleInputChange()">

import request from 'superagent';

handleInputChange = (event) => {
  console.log(event.target.files[0]);

  let fileObj = event.target.files[0];
  let name = '';
  let ext = '';
  fileObj.name.split('.').map((val, index, arr) => {
    if (index === arr.length - 1) ext += val;
    else name += val;
  });
  let size = fileObj.size;
  let type = fileObj.type;

  let reader = new FileReader();
  reader.readAsDataURL(fileObj);
  reader.onloadend = function(e) {
    request.post('/api/project-image/')
      .set({
        'Accept': 'application/json'
      })
      .send({
        projectName: 'test',
        file: e.target.result.split(',').pop(),
        name: name,
        ext: ext,
        type: type,
        size: size
      })
      .end(function(err, res) {
        if (err) {
          console.log(err);
        } else if (res) {
          const obj = assign({}, event);
          obj.field = props.field;
          obj.src = res.body.filename;
          obj.uid = props.uid;
          ActionCreator.editImage(obj);
          ActionCreator.toggleEditImage(obj);
        }
      });
  };
};

Ответ 5

Вот что сработало для меня. У меня была одна форма поля, которая загружала файл. Я превратил форму в элемент HTML5 FormData, а затем сделал это следующим образом:

var frm = new FormData(document.getElementById('formId'));
var url =  'url/here';

superagent.post(url)                    
.attach('fieldInFormName', frm.get('fieldInFormName'))                                        
.end( function (error, response) {
    //handle response
});

Обратите внимание, что я пробовал различные способы настройки "Content-Type" вручную в суперагенте, и он никогда не работал правильно из-за многочастного идентификатора, необходимого в Content-Type.