Как загрузить изображение в Slack с помощью node.js в Windows?

Я пытаюсь загрузить изображение через Slack, используя node.js и пакет запроса, но не имея много удачи. Либо я получаю invalid_array_arg или no_file_data ошибки от API.

Вот мой запрос:

    var options = { method: 'POST',
      url: 'https://slack.com/api/files.upload',
      headers: 
       { 'cache-control': 'no-cache',
         'content-type': 'application/x-www-form-urlencoded' },
      form: 
       { token: SLACK_TOKEN,
         channels: SLACK_CHANNEL,
         file: fs.createReadStream(filepath)
        } };

    request(options, function (error, response, body) {
      if (error) throw new Error(error);

      console.log(body);
    });

Я просмотрел несколько соответствующих сообщений:

Единственное, что сработало, это прямое использование команды curl, но с использованием cygwin (ошибка командной строки: curl: (1) Protocol https not supported or disabled in libcurl). Проблема с вызовом curl из узла (используя child_process), но который молча терпит неудачу в командной строке и по-прежнему возвращает no_file_data, используя cygwin (передавая абсолютный путь к файлу):

stdout: {"ok":false,"error":"no_file_data"}
stderr:   % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   469  100    35  100   434    359   4461 --:--:-- --:--:-- --:--:--  6112

Я использую узел v6.9.1 в Windows.

Что мне не хватает? Как я могу загрузить изображение в slack через node.js в Windows?


person George Profenza    schedule 06.02.2018    source источник
comment
Я знаю, что это не ответ на ваш вопрос, возможно, вам стоит подумать об использовании node-slack-sdk /, в этом случае вам не нужно реализовывать эту функцию самостоятельно. документация по загрузке файлов   -  person Peter    schedule 07.02.2018
comment
@Peter неожиданно получает ту же ошибку с node-slack-sdk:error: Response not OK: no_file_data Error: no_file_data   -  person George Profenza    schedule 07.02.2018
comment
@GeorgeProfenza можно использовать files.upload.   -  person Erik Kalkoken    schedule 07.02.2018
comment
почему решение из вашего связанного вопроса № 2 не работает для вас? (stackoverflow.com/questions/38084459/) вы пытались воспроизвести с таким же синтаксисом?   -  person Erik Kalkoken    schedule 07.02.2018
comment
Возможный дубликат Slack API (files.upload) с использованием NodeJS   -  person Erik Kalkoken    schedule 07.02.2018
comment
что говорит fs.createReadStream(filepath).stat()?   -  person Peter    schedule 07.02.2018
comment
в любом случае это тоже выглядит актуальным.   -  person Peter    schedule 07.02.2018
comment
@Питер console.log(fs.createReadStream(filename).stat()); ^ TypeError: fs.createReadStream(...).stat is not a function   -  person George Profenza    schedule 07.02.2018
comment
@ErikKalkoken Я упомянул в своем вопросе, что уже проверил вопрос, который вы пометили как дубликат. Я признаю, что они очень похожи, но решение там не работает в моем случае. Несмотря на то, что ошибка в конце такая же, источник ошибки может быть другим.   -  person George Profenza    schedule 07.02.2018
comment
Как насчет того, чтобы попробовать этот пример скрипта? gist.github.com/tanaikech/40c9284e91d209356395b43022ffc5cc В моей среде ваш скрипт также вызывает ту же ошибку . Поэтому я создал это. Если это не было для вас полезным, извините.   -  person Tanaike    schedule 07.02.2018
comment
@Tanaike, первый явный составной заголовок работал как шарм! Вы также должны опубликовать это как ответ: это очень полезно! Большое тебе спасибо   -  person George Profenza    schedule 08.02.2018
comment
Спасибо за ваш ответ. Я рад, что это было полезно для вас. Я выложил этот скрипт. Пожалуйста, подтвердите.   -  person Tanaike    schedule 09.02.2018
comment
Если у вас есть проблемы с моим примером сценария, пожалуйста, сообщите мне. Я хотел бы учиться на проблемах.   -  person Tanaike    schedule 11.02.2018
comment
@Tanaike Хотел бы я дать вам больше одного голоса. Оба решения сработали! Тем временем я провел больше тестов и обнаружил проблему: я пытался загрузить образ до того, как он был полностью записан на диск. Как только я убедился, что файл полностью записан на диск, второй метод тоже работает. Что интересно, ваш первый метод, ручное создание составного заголовка, работал, даже когда изображение не было полностью записано на диск: он просто отображал серые пиксели вместо отсутствующих данных.   -  person George Profenza    schedule 16.02.2018
comment
Спасибо за дополнительную информацию. Я рад, что ваша проблема была решена. А также я мог бы изучить ваш вопрос. И тебе спасибо.   -  person Tanaike    schedule 17.02.2018
comment
Привет @GeorgeProfenza, я столкнулся с той же ошибкой, и мне было интересно, как вы добились того, что ваш образ был полностью записан на диск. Вы сказали, что я пытался загрузить образ до того, как он был полностью записан на диск. Как только я гарантирую, что файл полностью записан на диск, методы сработали. Я пытаюсь отправить PDF вместо изображения, но получаю ту же ошибку, и у меня такое чувство, что это по той же причине.   -  person Carol Gonzalez    schedule 17.09.2019
comment
@CarolGonzalez В моем случае я загружал пару изображений, используя графическую магию, чтобы сделать их монтаж, а затем загружал результат, поэтому в моем случае процесс загрузки начинался с события 'close' gm. В вашем случае это может быть даже доступно слушателю, когда файл PDF завершит запись на диск. В качестве доказательства концепции вы можете попробовать взломать setTimeout до 10 секунд или что-то в этом роде (если PDF-файл не велик), чтобы изолировать проблему и подтвердить, что это та же проблема. Если это так, в идеале вы должны удалить хакерскую задержку и использовать правильное событие. Извините за задержку с возвратом.   -  person George Profenza    schedule 19.09.2019


Ответы (2)


Ошибка Slack API invalid_array_arg означает, что существует проблема с форматом аргументов, передаваемых в Slack. (см. здесь)

При использовании свойства file для files.upload Slack исключает данные как multipart/form-data, а не как application/x-www-form-urlencoded. Поэтому вместо form вам нужно использовать formData в вашем объекте запроса. Я также удалил неверную часть в шапке.

Это работает:

      var fs = require('fs');
      var request = require('request');

      var SLACK_TOKEN = "xoxp-xxx";
      var SLACK_CHANNEL = "general";
      var filepath = "file.txt";

      var options = { method: 'POST',
      url: 'https://slack.com/api/files.upload',
      headers: 
       { 'cache-control': 'no-cache' },
      formData: 
       { token: SLACK_TOKEN,
         channels: SLACK_CHANNEL,
         file: fs.createReadStream(filepath)
        } };

    request(options, function (error, response, body) {
      if (error) throw new Error(error);

      console.log(body);
    });
person Erik Kalkoken    schedule 07.02.2018
comment
Спасибо за ваш ответ. Я пытался использовать formData, как вы предложили выше, к сожалению, я получаю ту же ошибку. Я проведу еще несколько тестов. Возможно, данные, которые я загружаю, не готовы? - person George Profenza; 08.02.2018
comment
@GeorgeProfenza Этот код протестирован и работает. Я добавил инициализацию, чтобы убедиться. Вы пробовали именно этот код? И, пожалуйста, дайте мне знать, какую именно ошибку вы получаете от API. - person Erik Kalkoken; 08.02.2018
comment
Простите за опоздание. Я провел еще несколько тестов и нашел источник проблемы: не сам запрос, а данные и результаты createReadStream. Я не стал ждать, пока изображение, которое я загружал, будет полностью записано на диск перед загрузкой. Теперь это исправлено, и ваш код, и код Танайке работают. Интересная вещь в его ручном многокомпонентном подходе заключается в том, что он работал, даже когда jpeg не был полностью записан на диск (отображение jpeg в правильных размерах с небольшой частью серых пикселей). - person George Profenza; 16.02.2018

В этом примере сценария предполагается загрузить двоичный файл (zip-файл). Когда вы используете это, пожалуйста, измените для своей среды. Когда файлы загружаются в Slack, используются multipart/form-data. В моей среде были ситуации, когда файлы не могли быть загружены некоторыми библиотеками. Поэтому я создал это. Если это полезно для вашей среды, я рад.

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

  • Сначала он строит данные формы.
  • Добавляет zip-файл, преобразованный в массив байтов, и границу с помощью Buffer.concat().
  • Это используется как тело в запросе.

Пример сценария выглядит следующим образом.

Пример сценария:

var fs = require('fs');
var request = require('request');
var upfile = 'sample.zip';
fs.readFile(upfile, function(err, content){
    if(err){
        console.error(err);
    }
    var metadata = {
        token: "### access token ###",
        channels: "sample",
        filename: "samplefilename",
        title: "sampletitle",
    };
    var url = "https://slack.com/api/files.upload";
    var boundary = "xxxxxxxxxx";
    var data = "";
    for(var i in metadata) {
        if ({}.hasOwnProperty.call(metadata, i)) {
            data += "--" + boundary + "\r\n";
            data += "Content-Disposition: form-data; name=\"" + i + "\"; \r\n\r\n" + metadata[i] + "\r\n";
        }
    };
    data += "--" + boundary + "\r\n";
    data += "Content-Disposition: form-data; name=\"file\"; filename=\"" + upfile + "\"\r\n";
    data += "Content-Type:application/octet-stream\r\n\r\n";
    var payload = Buffer.concat([
            Buffer.from(data, "utf8"),
            new Buffer(content, 'binary'),
            Buffer.from("\r\n--" + boundary + "\r\n", "utf8"),
    ]);
    var options = {
        method: 'post',
        url: url,
        headers: {"Content-Type": "multipart/form-data; boundary=" + boundary},
        body: payload,
    };
    request(options, function(error, response, body) {
        console.log(body);
    });
});
person Tanaike    schedule 08.02.2018