【问题标题】:nodejs-slackbot - downloaded file is corruptednodejs-slackbot - 下载的文件已损坏
【发布时间】:2022-01-20 23:48:19
【问题描述】:

我使用 @slack/bolt 创建了一个带有 nodejs 的 slackbot。 每当我用我的 slackapp 标记并发送 textMessage 或 textMessage+Fileattachment 时,我都能够从 slack 接收我的 nodejs 服务器中的事件。请在下面找到事件对象的nodejs源代码和输出。

问题是,当我在 slack 中上传文件时,我的 nodejs slack-bot 收到了该事件。 (如下图所示+在下面附加的输出中查看事件对象详细信息)

  • nodejs slack-bot 从事件对象中检索到上传文件的链接
  • 我可以使用网络浏览器(例如谷歌浏览器)中的链接来查看上传的文件。
  • 当我使用链接通过 nodejs 代码下载文件时,文件被下载,但下载的文件已损坏

我不确定如何使用 nodejs slack-bot 下载有效文件。我尝试更改一些参数和设置,但没有成功。到目前为止,文档对我没有帮助

请帮帮我

Nodejs 源代码

const { App : BoltApp } = require('@slack/bolt');
const boltAppObj = new BoltApp({
    token: constants.BOT_TOKEN, 
    appToken: constants.SLACK_APP_TOKEN,
    socketMode: true,
    scopes:["files:read","files:write"]
});
  
(async () => {
    await boltAppObj.start();
    console.log('⚡️ Bolt app started');


    boltAppObj.event('app_mention', async ({ event, context, client, say }) => {
        console.log("in app_mention")
        console.log("event ",event)
        try {
          await say({"blocks": [
            {
              "type": "section",
              "text": {
                "type": "mrkdwn",
                "text": `Thanks for the mention <@${event.user}>!`
              } 
            }
          ]});
        }
        catch (error) {
          console.error(error);
        }
      });
})();


输出

event  {
  type: 'app_mention',
  text: '<@U01NJR8JNDQ> good morning have a nice day',
  files: [
    {
      id: 'F01P0V0SC9X',
      created: 1613713912,
      timestamp: 1613713912,
      name: 'hiddencloudvillage.png',
      title: 'hiddencloudvillage.png',
      mimetype: 'image/png',
      filetype: 'png',
      pretty_type: 'PNG',
      user: 'U01NJPG7RGS',
      editable: false,
      size: 18207,
      mode: 'hosted',
      is_external: false,
      external_type: '',
      is_public: true,
      public_url_shared: false,
      display_as_bot: false,
      username: '',
      url_private: 'https://files.slack.com/files-pri/T01NC0NH1KQ-F01P0V0SC9X/hiddencloudvillage.png',
      url_private_download: 'https://files.slack.com/files-pri/T01NC0NH1KQ-F01P0V0SC9X/download/hiddencloudvillage.png',
      thumb_64: 'https://files.slack.com/files-tmb/T01NC0NH1KQ-F01P0V0SC9X-9f0babf31c/hiddencloudvillage_64.png',
      thumb_80: 'https://files.slack.com/files-tmb/T01NC0NH1KQ-F01P0V0SC9X-9f0babf31c/hiddencloudvillage_80.png',
      thumb_360: 'https://files.slack.com/files-tmb/T01NC0NH1KQ-F01P0V0SC9X-9f0babf31c/hiddencloudvillage_360.png',
      thumb_360_w: 360,
      thumb_360_h: 360,
      thumb_480: 'https://files.slack.com/files-tmb/T01NC0NH1KQ-F01P0V0SC9X-9f0babf31c/hiddencloudvillage_480.png',
      thumb_480_w: 480,
      thumb_480_h: 480,
      thumb_160: 'https://files.slack.com/files-tmb/T01NC0NH1KQ-F01P0V0SC9X-9f0babf31c/hiddencloudvillage_160.png',
      original_w: 640,
      original_h: 640,
      thumb_tiny: 'AwAwADDToqtPfRRP5YDO/ooqP+0VU/vIZUHqRQBdoqCW7iiiV87g33Qveof7Q/6d5fyoAu0VS/tD/p3l/KpIL2OaTyyrI/YMOtAEb208U7y2zr85yysKRkvplKOYkU8HHNXqz9r3lzMplZEjOAq0AJLbtatbvGpkWPII7/Wp/t8X2fzcN97btxzmmf2ee1zN+dO+wR/Z/K3Nndu3d80AN/tFf+eEv5UwM95dROsTIkZyWYdafZvItxLbvIZAnIY9au0AFVprJJZPMVmjc9Sp61ZooApf2ef+fmb86P7PP/PzN+dXaKAIbe2S3UhMknqx6mpqKKAP/9k=',
      permalink: 'https://pov-vtapbot.slack.com/files/U01NJPG7RGS/F01P0V0SC9X/hiddencloudvillage.png',
      permalink_public: 'https://slack-files.com/T01NC0NH1KQ-F01P0V0SC9X-df55a3dc04',
      is_starred: false,
      has_rich_preview: false
    }
  ],
  upload: false,
  blocks: [ { type: 'rich_text', block_id: 'ZecUF', elements: [Array] } ],
  user: 'U01NJPG7RGS',
  display_as_bot: false,
  ts: '1613713934.000900',
  channel: 'C01NXCJ2EN5',
  event_ts: '1613713934.000900'
}

使用事件对象中可用的 url 下载文件的脚本

const axios=require("axios");
const fs = require("fs")
const constants = require("./constants");

let url="https://files.slack.com/files-pri/T01NC0NH1KQ-F01N7CHRGF9/download/poc.xlsx";
const config = {
    headers: { Authorization: `Bearer ${constants.SLACK_APP_TOKEN}` }
};
axios({
    method: "GET",
    url  : url,
    responseType: "stream",
    headers : config.headers
}).then((result)=>{
    console.log("result ")
    result.data.pipe(fs.createWriteStream("./poc.xlsx"));

}).catch((err)=>{
    console.log("err ");
})

【问题讨论】:

    标签: node.js slack slack-api


    【解决方案1】:
    • 问题在于传递给文件下载 api 的令牌类型
    • BOT_TOKEN 是必须传递给文件下载 api 的适当令牌
    • 当我将BOT_TOKEN 传递给文件下载 api 后问题得到解决

    以下是下载在 slack 中上传的文件的逻辑

    const downloadFile= (url,filename)=>{
    
        let fullFilePath = "";
        const promise = new Promise((resolve,reject)=>{
            const config = {
                headers: { Authorization: `Bearer ${constants.BOT_TOKEN}` }
            };
            axios({
                method: "GET",
                url  : url,
                responseType: "stream",
                headers : config.headers
            }).then((result)=>{
                const writeStream = fs.createWriteStream(fullFilePath);
                result.data.on('data', (chunk) => {
                    writeStream.write(chunk);
                });
                result.data.on('end', function () {
                    writeStream.uncork();
                    writeStream.close();
                    writeStream.end();
                    console.log("completely ending the pipe");
                });
                writeStream.on('finish', () => {
                    resolve(fullFilePath);
                });
                // This is here incase any errors occur
                writeStream.on('error', function (err) {
                    reject(err);
                });
            }).catch((err)=>{
                reject(err);
            });
        });
        return promise;
    };
    

    以下是 nodejs-slackbot 集成的示例逻辑

    const constants = require("./constants");
    const { App : BoltApp } = require('@slack/bolt');
    const utility = require("./utility");
    const path = require("path");
    
    const BOT_PORT = 3000;
    const boltAppObj = new BoltApp({
        token: constants.BOT_TOKEN, 
        signingSecret : constants.SLACK_SIGNING_SECRET,
    });
      
    const sendMessageToSlack= async (event,say,chatmessage)=>{
        await say({
            text: `Hey there <@${event.user}>! , ${chatmessage}`
          });
    }
    
    (async () => {
        await boltAppObj.start(BOT_PORT);
        console.log('⚡️ Bolt app started');
    
        boltAppObj.event('app_mention', async ({ event, context, client, say }) => {
            const textMessage = event.text;
            try{
                const filePath = await utility.getLocalFilePath(event.files ? event.files : null);
                sendMessageToSlack(event,say,"success");
            }
            catch(err){
                sendMessageToSlack(event,say,"failed");
            }
        })
    
    })();
    
    

    如果您遇到与此主题相关的任何问题,请随时与我联系

    回复@ppp 的评论

    请验证您在 slack 网站上创建的 slackbot 应用程序中是否存在 files:read 权限

    【讨论】:

    • 我假设BOT_TOKEN 是指以xoxb- 开头的令牌字符串(机器人用户OAuth 令牌)?我正在尝试使用您的代码,但我无法终生下载文件而不会最终在本地损坏。就像你一样 - 我从事件对象中检索到上传文件的链接,我可以使用 Chrome 中的链接查看(和下载)上传的文件,文件将通过 Node 下载,但下载的文件是损坏。
    • 请查看我更新的答案,如果有帮助请告诉我@ppp
    • 感谢您使用屏幕截图更新您的答案。我可以确认files:read 机器人令牌范围在那里。我还设法通过curl 使用我的令牌成功下载了文件 - 所以我知道令牌具有正确的范围。在这一点上,只有 Node 给我一个损坏的下载。
    • @ppp 您是否使用url_private_download 中的链接通过nodejs 下载文件?
    猜你喜欢
    • 2018-03-20
    • 1970-01-01
    • 1970-01-01
    • 2014-08-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多