使用 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 证书

先决条件

  • 一个 IoT 中心。 使用 CLIAzure 门户创建一个。

  • 已注册的设备。 在 Azure 门户中注册一个。

  • 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 中心左侧窗格上的“文件上传”。

    Screen capture showing select file upload settings from the portal.

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

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

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

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

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

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

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

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

    Screen capture showing confirm file upload settings in the portal.

有关如何创建 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. 复制“主连接字符串”并保存该值。

Screenshot that shows how to retrieve the connection string from your IoT Hub in the Azure portal.

有关 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。

    Screenshot of viewing the uploaded file in the Azure portal.

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

后续步骤

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