使用 Azure IoT 中心将文件从设备上传到云 (Node.js)

本文演示 IoT 中心的文件上传功能如何使用 Node.js 将文件上传到 Azure Blob 存储

使用 IoT 中心发送云到设备的消息一文介绍了 IoT 中心提供的基本的云到设备的消息传送功能。 使用 IoT 中心配置消息路由教程介绍了一种在 Azure Blob 存储中可靠存储设备到云消息的方法。 但是,在某些情况下,无法轻松地将设备发送的数据映射为 IoT 中心接受的相对较小的设备到云消息。 例如:

  • 视频
  • 包含图像的大型文件
  • 以高频率采样的振动数据
  • 某种形式的预处理数据。

通常使用 Azure 数据工厂Hadoop 堆栈等工具在云中批处理这些文件。 需要从设备上传文件时,仍可以使用 IoT 中心的安全性和可靠性。 本文介绍如何进行此操作。

在本文结束时,会运行两个 Node.js 控制台应用:

  • FileUpload.js,它使用 IoT 中心提供的 SAS URI 将文件上传到存储。

  • FileUploadNotification.js,它接收来自 IoT 中心的文件上传通知。

注意

IoT 中心通过 Azure IoT 设备 SDK 来支持许多设备平台和语言(包括 C、Java、Python 和 JavaScript)。 请参阅 Azure IoT 开发人员中心,了解如何将设备连接到 Azure IoT 中心。

重要

使用 X.509 证书颁发机构 (CA) 身份验证的设备上的文件上传功能为公共预览版,并且必须启用预览模式。 这是在一同使用 X.509 指纹身份验证或 X.509 证书证明与 Azure 设备预配服务的设备上的正式发布版本。 若要了解有关使用 IoT 中心进行 X.509 身份验证的详细信息,请参阅支持的 X.509 证书

先决条件

  • Azure 订阅中的 IoT 中心。 如果还没有中心,则可以按照创建 IoT 中心中的步骤进行操作。

  • 在 IoT 中心注册的设备。 如果 IoT 中心没有设备,请按照注册设备中的步骤操作。

  • Node.js 版本 10.0.x 或更高版本。 建议使用 LTS 版本。 可以从 nodejs.org 下载 Node.js。

  • 端口 8883 在防火墙中须处于打开状态。 本文中的设备示例使用 MQTT 协议,该协议通过端口 8883 进行通信。 在某些公司和教育网络环境中,此端口可能被阻止。 有关解决此问题的更多信息和方法,请参阅连接到 IoT 中心(MQTT)

将 Azure 存储帐户关联到 IoT 中心

若要从设备上传文件,必须拥有与 IoT 中心关联的 Azure 存储帐户和 Azure Blob 存储容器。 将存储帐户和容器与 IoT 中心关联后,IoT 中心可以在设备请求时提供 SAS URI 的元素。 然后,设备可以使用这些元素来构造 SAS URI,并将其用于向 Azure 存储进行身份验证,以及上传文件到 blob 容器。

将 Azure 存储帐户与 IoT 中心关联:

  1. 在“中心设置”下,选择 IoT 中心左侧窗格上的“文件上传”。

    显示从门户中选择“文件上传”设置的屏幕截图。

  2. 在“文件上传”窗格中,选择“Azure 存储容器” 。 对于本文,建议你的存储帐户和 IoT 中心位于同一区域。

    • 如果你已有要使用的存储帐户,请从列表中选择它。

    • 若要创建新的存储帐户,请选择“+存储帐户”。 为该存储帐户命名,并确保其位置设置为 IoT 中心的同一区域,然后选择“确定” 。 将在 IoT 中心的同一资源组中创建新帐户。 部署完成后,从列表中选择“存储帐户”。

    选择“存储帐户”后,将打开“容器”窗格。

  3. 在“容器”窗格中,选择“blob 容器”。

    • 如果已有要使用的 blob 容器,请从列表中选择它,然后单击“选择”。

    • 然后选择“新建容器”以创建新的 blob 容器。 为新容器命名。 出于本文的目的,可以将其他所有字段保留为默认值。 选择“创建”。 部署完成后,从列表中选择“容器”,然后单击“选择”。

  4. 回到“文件上传”窗格,确保文件通知设置为“开启” 。 可将其他所有设置保留默认值。 选择“保存”并等待设置完成,然后进入下一部分。

    显示在门户中确认文件上传设置的屏幕截图。

有关如何创建 Azure 存储帐户的详细说明,请参阅创建存储帐户。 若要了解如何将存储帐户以及 blob 容器与 IoT 中心关联的详细信息,请参阅使用 Azure 门户配置文件上传

从设备应用上传文件

在本部分,我们创建将文件上传到 IoT 中心的设备应用。 该代码基于 Azure IoT Node.js SDK 设备示例中的 upload_to_blob_advanced.js 示例中提供的代码。

  1. 创建名为 fileupload 的空文件夹。 在 fileupload 文件夹的命令提示符处,使用以下命令创建 package.json 文件。 接受所有默认值:

    npm init
    
  2. fileupload 文件夹的命令提示符处,运行以下命令来安装 azure-iot-device 设备 SDK、azure-iot-device-mqtt 和 @azure/storage-blob 包:

    npm install azure-iot-device azure-iot-device-mqtt @azure/storage-blob --save
    
  3. 使用文本编辑器,在 fileupload 文件夹中创建一个 FileUpload.js 文件,并将以下代码复制到其中。

    'use strict';
    
    const Client = require('azure-iot-device').Client;
    const Protocol = require('azure-iot-device-mqtt').Mqtt;
    const errors = require('azure-iot-common').errors;
    const path = require('path');
    
    const {
      AnonymousCredential,
      BlockBlobClient,
      newPipeline
    } = require('@azure/storage-blob');
    
    // make sure you set these environment variables prior to running the sample.
    const deviceConnectionString = process.env.DEVICE_CONNECTION_STRING;
    const localFilePath = process.env.PATH_TO_FILE;
    const storageBlobName = path.basename(localFilePath);
    
    async function uploadToBlob(localFilePath, client) {
      const blobInfo = await client.getBlobSharedAccessSignature(storageBlobName);
      if (!blobInfo) {
        throw new errors.ArgumentError('Invalid upload parameters');
      }
    
      const pipeline = newPipeline(new AnonymousCredential(), {
        retryOptions: { maxTries: 4 },
        telemetry: { value: 'HighLevelSample V1.0.0' }, // Customized telemetry string
        keepAliveOptions: { enable: false }
      });
    
      // Construct the blob URL to construct the blob client for file uploads
      const { hostName, containerName, blobName, sasToken } = blobInfo;
      const blobUrl = `https://${hostName}/${containerName}/${blobName}${sasToken}`;
    
      // Create the BlockBlobClient for file upload to the Blob Storage Blob
      const blobClient = new BlockBlobClient(blobUrl, pipeline);
    
      // Setup blank status notification arguments to be filled in on success/failure
      let isSuccess;
      let statusCode;
      let statusDescription;
    
      try {
        const uploadStatus = await blobClient.uploadFile(localFilePath);
        console.log('uploadStreamToBlockBlob success');
    
        // Save successful status notification arguments
        isSuccess = true;
        statusCode = uploadStatus._response.status;
        statusDescription = uploadStatus._response.bodyAsText;
    
        // Notify IoT Hub of upload to blob status (success)
        console.log('notifyBlobUploadStatus success');
      }
      catch (err) {
        isSuccess = false;
        statusCode = err.code;
        statusDescription = err.message;
    
        console.log('notifyBlobUploadStatus failed');
        console.log(err);
      }
    
      await client.notifyBlobUploadStatus(blobInfo.correlationId, isSuccess, statusCode, statusDescription);
    }
    
    // Create a client device from the connection string and upload the local file to blob storage.
    const deviceClient = Client.fromConnectionString(deviceConnectionString, Protocol);
    uploadToBlob(localFilePath, deviceClient)
      .catch((err) => {
        console.log(err);
      })
      .finally(() => {
        process.exit();
      });
    
  4. 保存并关闭 FileUpload.js 文件。

  5. 将图像文件复制到 fileupload 文件夹,并为其指定名称,例如 myimage.png

  6. 为设备连接字符串添加环境变量并添加要上传的文件的路径。 在 IoT 中心注册设备时,你收到了设备连接字符串。

    • 对于 Windows:

      set DEVICE_CONNECTION_STRING={your device connection string}
      set PATH_TO_FILE={your image filepath}
      
    • 对于 Linux/Bash:

      export DEVICE_CONNECTION_STRING="{your device connection string}"
      export PATH_TO_FILE="{your image filepath}"
      

获取 IoT 中心连接字符串

在本文中,你将创建一项后端服务,用于从你创建的 IoT 中心接收文件上传通知消息。 若要接收文件上传通知消息,服务需要服务连接权限。 默认情况下,每个 IoT 中心都使用名为“服务”的共享访问策略创建,该策略会授予此权限。

若要获取 service策略的 IoT 中心连接字符串,请执行以下步骤:

  1. Azure 门户中,选择“资源组”。 选择中心所在的资源组,然后从资源列表中选择中心。

  2. 在 IoT 中心的左侧窗格上,选择“共享访问策略”。

  3. 在策略列表中,选择“service”策略。

  4. 复制“主连接字符串”并保存该值。

屏幕截图显示如何在 Azure 门户中从 IoT 中心检索连接字符串。

有关 IoT 中心共享访问策略和权限的详细信息,请参阅访问控制和权限

接收文件上传通知

本部分中的操作将会创建一个 Node.js 控制台应用,用于接收来自 IoT 中心的文件上传通知消息。

  1. 创建名为 fileuploadnotification 的空文件夹。 在 fileuploadnotification 文件夹的命令提示符处,使用以下命令创建 package.json 文件。 接受所有默认值:

    npm init
    
  2. fileuploadnotification 文件夹中的命令提示符下,运行以下命令安装 azure-iothub SDK 包:

    npm install azure-iothub --save
    
  3. 使用文本编辑器在 fileuploadnotification 文件夹中创建 FileUploadNotification.js 文件。

  4. FileUploadNotification.js 文件的开头添加以下 require 语句:

    'use strict';
    
    const Client = require('azure-iothub').Client;
    
  5. 从环境中读取 IoT 中心的连接字符串:

    const connectionString = process.env.IOT_HUB_CONNECTION_STRING;
    
  6. 添加以下代码,从连接字符串创建服务客户端:

    const serviceClient = Client.fromConnectionString(connectionString);
    
  7. 打开客户端,并使用 getFileNotificationReceiver 函数接收状态更新。

    serviceClient.open(function (err) {
      if (err) {
        console.error('Could not connect: ' + err.message);
      } else {
        console.log('Service client connected');
        serviceClient.getFileNotificationReceiver(function receiveFileUploadNotification(err, receiver){
          if (err) {
            console.error('error getting the file notification receiver: ' + err.toString());
          } else {
            receiver.on('message', function (msg) {
              console.log('File upload from device:')
              console.log(msg.getData().toString('utf-8'));
              receiver.complete(msg, function (err) {
                if (err) {
                  console.error('Could not finish the upload: ' + err.message);
                } else {
                  console.log('Upload complete');
                }
              });
            });
          }
        });
      }
    });
    

    注意

    如果要在侦听文件上传通知时接收断开连接通知,则需要通过使用 receiver.on 来注册 'error'。 若要继续接收文件上传通知,则需要通过使用 serviceClient.open 方法来重新连接到 IoT 中心。

  8. 保存并关闭 FileUploadNotification.js 文件。

  9. 为 IoT 中心连接字符串添加环境变量。 你先前在获取 IoT 中心连接字符串中复制了此字符串。

    • 对于 Windows:

      set IOT_HUB_CONNECTION_STRING={your iot hub connection string}
      
    • 对于 Linux/Bash:

      export IOT_HUB_CONNECTION_STRING="{your iot hub connection string}"
      

运行应用程序

现在已准备就绪,可以运行应用程序了。

fileuploadnotification 文件夹中的命令提示符下运行以下命令:

node FileUploadNotification.js

fileupload 文件夹中的命令提示符下运行以下命令:

node FileUpload.js

以下输出来自上传完成后的 FileUpload 应用:

uploadStreamToBlockBlob success
notifyBlobUploadStatus success

以下示例输出来自上传完成后的 FileUploadNotification 应用:

Service client connected
File upload from device:
{"deviceId":"myDeviceId","blobUri":"https://{your storage account name}.blob.core.chinacloudapi.cn/device-upload-container/myDeviceId/image.png","blobName":"myDeviceId/image.png","lastUpdatedTime":"2021-07-23T23:27:06+00:00","blobSizeInBytes":26214,"enqueuedTimeUtc":"2021-07-23T23:27:07.2580791Z"}

验证文件上传

可以使用门户查看所配置的存储容器中上传的文件:

  1. 在 Azure 门户中导航到存储帐户。

  2. 在存储帐户的左侧窗格中,选择“容器”。

  3. 选择已将文件上传到其中的容器。

  4. 选择与设备同名的文件夹。

  5. 选择已将文件上传到其中的 Blob。 在本文中,它是与你的文件同名的 Blob。

    在 Azure 门户中查看上传的文件的屏幕截图。

  6. 在打开的页面上查看 Blob 属性。 可以选择“下载”,以将该文件下载到本地并查看其内容。

后续步骤

在本文中,你已学习了如何使用 IoT 中心的文件上传功能来简化从设备进行的文件上传。 可以继续通过以下文章了解此功能: