【问题标题】:Azure: Function stops working when trying to get blob contentAzure:尝试获取 blob 内容时函数停止工作
【发布时间】:2019-12-20 19:43:57
【问题描述】:

我正在使用 nodeJS 和 Azure 函数。我正在尝试获取 blob(pptx)的内容,然后进一步使用该 pptx(使用 admzip 解压缩)。

但是,每当我尝试获取内容时,该功能都会停止而没有任何错误,并且在一段时间后会超时。我尝试首先获取 blob 的属性(以检查 blob 是否存在)并且有效。

这是我的功能:

const storage = require('azure-storage');
const STORAGE_ACCOUNT_NAME = 'storage-account';
const ACCOUNT_ACCESS_KEY = 'storage-key';
let AdmZip = require('adm-zip');
let fs = require('file-system');

const blobService = storage.createBlobService(STORAGE_ACCOUNT_NAME, ACCOUNT_ACCESS_KEY);

module.exports = function (context, req) {
    context.log('JavaScript HTTP trigger function processed a request.');
    getBlobProperties('default-powerpoint', 'download.pptx').then((properties) => {
        context.log('Properties: ', properties);
        getBlobContent('default-powerpoint', 'download.pptx').then((content) => {
            context.log('Blob Content: ', content);
        })
    });
};

function getBlobProperties(containerName, fileName) {
    return new Promise((resolve, reject) => {
        blobService.getBlobProperties(
            containerName,
            fileName,
            function (err, properties, status) {
                if (err) {
                    reject(err);
                } else {
                    resolve(properties);
                }
            });
    })
}

function getBlobContentAsStream(containerName, fileName, res) {
    return new Promise((resolve, reject) => {
        blobService.getBlobToStream(containerName, fileName, res, function (err, results) {
            if (err) {
                reject(err);
            } else {
                resolve(JSON.stringify(results, null, 2));
            }
        });
    })
}

function getBlobContent(containerName, blobName) {
    return new Promise((resolve, reject) => {
        blobService.getBlobToText(
            containerName,
            blobName,
            function (err, blobContent, blob) {
                if (err) {
                    reject(err);
                } else {
                    resolve({
                        'content': blobContent,
                        'blob': blob
                    });
                }
            });
    })
}

如您所见,我尝试了getBlobToStreamgetBlobToText,但结果相同。 getBlobProperties 工作正常,我得到了关于 blob 的所有信息,只是没有内容。

谁能帮我获取 blob 的内容。

编辑

如果有人感兴趣,这是属性的输出:

BlobResult {
  container: 'default-powerpoint',
  name: 'download.pptx',
  metadata: {},
  lastModified: 'Wed, 14 Aug 2019 08:28:16 GMT',
  creationTime: 'Wed, 14 Aug 2019 08:28:16 GMT',
  etag: '"something"',
  blobType: 'BlockBlob',
  contentLength: '4658',
  serverEncrypted: 'true',
  requestId: 'someID',
  contentSettings: { contentType: 'image/jpeg' },
  lease: { status: 'unlocked', state: 'available' },
  copy: 
   { id: 'id123',
     status: 'success',
     source: 'sourceURL',
     progress: '4658/4658',
     bytesCopied: 4658,
     totalBytes: 4658,
     completionTime: 'Wed, 14 Aug 2019 08:28:16 GMT' } }

【问题讨论】:

  • 可能不相关,但为什么您的内容类型是 'image/jpeg' ?
  • 这也是运行时 v1 还是 v2?以及哪个版本的节点?
  • @AdamMarczak 其节点版本 11.9 和运行时版本:2.0.12641.0 (~2)。内容类型可以忽略(我添加了一张图片,看看它是否与 powerpoint 类型有关,忘记添加 pptx 的输出,但尽管内容类型输出完全相同,稍后会更新)
  • 请记住,在 2.0 中,您需要调用 context.done(); 或导出异步函数 module.exports = async function。但我不确定这是不是一个问题,我回家后会检查一下。
  • @AdamMarczak 谢谢!我将尝试 context.done() 并更新输出

标签: node.js azure azure-functions azure-blob-storage


【解决方案1】:

这是我在应用中使用的工作代码

  return new Promise(async r => {
            bst.getBlobToText(containername, name, (err, text) => r(err ? null : text));
  })

Full SourceCode

【讨论】:

  • 我重新创建了 OP 场景并使用您的代码对其进行了测试。错误消息是相同的An incorrect number of bytes was read from the connection. The connection may have been closed,所以不幸的是这并不能解决它。您的代码适用于文本文件而不是二进制缓冲区文件。
【解决方案2】:

我能够使用代码解决这个问题

const storage = require('azure-storage');
const fs = require('fs');

const STORAGE_ACCOUNT_NAME = '<account_name>';
const ACCOUNT_ACCESS_KEY = '<access_key>';

const blobService = storage.createBlobService(STORAGE_ACCOUNT_NAME, ACCOUNT_ACCESS_KEY);

function getBlobContentAsStream(containerName, fileName, res) {
    return new Promise((resolve, reject) => {
        blobService.getBlobToStream(containerName, fileName, fs.createWriteStream('task1-download.txt'), function(error, serverBlob) {
            if(!error) {
                resolve(serverBlob);
            } else { 
                reject(err); 
            }
        });
    })
}

module.exports = function (context, req) {
    context.log('JavaScript HTTP trigger function processed a request.');

    context.log('Starting...');

    getBlobContentAsStream('default-powerpoint', 'download.pptx').then((content) => {
        context.log('Blob Content: ', content);
        context.done();
    }, function(err) {
        console.log.error(err);
        context.done();
    });

};

并跟踪输出

如果您将函数连接到代码中,您实际上可以在 Application Insights 跟踪中看到代码中发生的问题。您没有收到任何错误,因为您没有为 then 回调执行程序添加错误处理。

getBlobContent('default-powerpoint', 'download.pptx').then((content) => {
    context.log('Blob Content: ', content);
    context.done();
})

使用

getBlobContent('default-powerpoint', 'download.pptx').then((content) => {
    context.log('Blob Content: ', content);
    context.done();
}, function(err) {
    console.log(err);
    context.done();
}))

你会看到

详细说明

Error: An incorrect number of bytes was read from the connection. 
The connection may have been closed.

所以getBlobToText 遇到的问题是它试图将 Buffer 对象作为字符串返回,但无法验证 MD5。我在某处读到可以使用 write to stream 函数写入缓冲区而不是文件,但我现在找不到它。

我可能会抓取一些 NodeJS 内存流库并尝试在那里输出它,因为我假设您不想直接保存到文件中。但也许你愿意,自己决定。

如果您最终要使用“fs”库,请记住使用推荐的安全非阻塞模式,例如

const fs = require('fs');
const util = require('util');
const readFileAsync = util.promisify(fs.readFile);

module.exports = async function (context) {
    try {
        const data = await readFileAsync('./hello.txt');
    } catch (err) {
        context.log.error('ERROR', err);
        // This rethrown exception will be handled by the Functions Runtime and will only fail the individual invocation
        throw err;
    }
    context.log(`Data from file: ${data}`);
}

【讨论】:

  • @threxx 这有帮助吗?你测试过这个吗?
  • 是的,错误处理有效。 “我假设您不想直接保存到文件”是什么意思?我需要该文件,更改某些内容然后将其保存回来,这仍然适用于 fs 库和流吗?
  • 我的意思是直接保存到文件系统,因为不推荐使用“file.pptx”,因为在并行执行时可能会遇到问题。最好的解决方案是在内存流中使用,而不是将其保存在系统驱动器上。
【解决方案3】:

问题可能是 api 已更改。我刚刚在下面检查过,回调函数在getBlobToText 中只接受两个参数:

https://github.com/Azure-Samples/storage-blobs-node-quickstart/blob/master/index.js

const downloadBlob = async (containerName, blobName) => {
    const dowloadFilePath = path.resolve('./' + blobName.replace('.txt', '.downloaded.txt'));
    return new Promise((resolve, reject) => {
        blobService.getBlobToText(containerName, blobName, (err, data) => {
            if (err) {
                reject(err);
            } else {
                resolve({ message: `Blob downloaded "${data}"`, text: data });
            }
        });
    });
};

【讨论】:

    猜你喜欢
    • 2019-12-11
    • 2018-10-21
    • 2015-08-21
    • 2020-06-25
    • 2021-06-27
    • 2023-03-22
    • 1970-01-01
    • 2020-02-14
    • 2020-09-03
    相关资源
    最近更新 更多