จะอัพโหลดรูปภาพไปยัง 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 (CommandPrompt ล้มเหลว: curl: (1) Protocol https not supported or disabled in libcurl) ปัญหาในการเรียก curl จากโหนด (โดยใช้ child_process) แต่ล้มเหลวอย่างเงียบ ๆ ใน Command Prompt และยังคงส่งคืน 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

ฉันพลาดอะไรไป? ฉันจะอัพโหลดรูปภาพเพื่อหย่อนผ่าน 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 ในกรณีของฉัน ฉันกำลังดาวน์โหลดรูปภาพสองสามภาพ โดยใช้เวทมนตร์กราฟิกเพื่อสร้างภาพตัดต่อ จากนั้นอัปโหลดผลลัพธ์ ดังนั้นในกรณีของฉันเริ่มกระบวนการอัปโหลดจากเหตุการณ์ gm's 'close' ในกรณีของคุณ อาจมี Listener ให้ใช้เมื่อไฟล์ 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 ฉันไม่ได้รอให้ภาพที่ฉันกำลังอัปโหลดถูกเขียนลงดิสก์อย่างสมบูรณ์ก่อนที่จะอัปโหลด ขณะนี้ได้รับการแก้ไขแล้ว และทั้งโค้ดของคุณและโค้ดของ Tanaike ก็ใช้งานได้ สิ่งที่น่าสนใจเกี่ยวกับวิธีการแบ่งส่วนแบบแมนนวลของเขาคือมันใช้งานได้แม้ว่า jpeg จะไม่ได้เขียนลงดิสก์ทั้งหมดก็ตาม (แสดง jpeg ในขนาดที่ถูกต้องพร้อมกับส่วนเล็ก ๆ ของพิกเซลสีเทา) - person George Profenza; 16.02.2018

ในสคริปต์ตัวอย่างนี้ ควรจะอัปโหลดไฟล์ไบนารี (ไฟล์ zip) เมื่อคุณใช้สิ่งนี้ โปรดแก้ไขให้เหมาะกับสภาพแวดล้อมของคุณ เมื่อไฟล์ถูกอัปโหลดไปยัง Slack ระบบจะใช้ข้อมูลหลายส่วน/ฟอร์ม ในสภาพแวดล้อมของฉัน มีบางสถานการณ์ที่บางไลบรารีไม่สามารถอัพโหลดไฟล์ได้ ฉันจึงสร้างสิ่งนี้ขึ้นมา หากสิ่งนี้มีประโยชน์ต่อสภาพแวดล้อมของคุณ ฉันยินดี

ผู้ใช้สามารถอัพโหลดไฟล์ไบนารี่ได้โดยการแปลงอาร์เรย์ไบต์ดังนี้

  • ในตอนแรกมันจะสร้างฟอร์ม-ข้อมูล
  • เพิ่มไฟล์ 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