

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# 使用二进制有效载荷
<a name="binary-payloads"></a>

当将消息有效载荷作为原始二进制数据（而不是 JSON 对象）进行处理时，可以使用 \$1 运算符在 SELECT 子句中对其进行引用。

**Topics**
+ [

## 二进制有效载荷示例
](#binary-payloads-examples)
+ [

## 解码 protobuf 消息有效载荷
](#binary-payloads-protobuf)

## 二进制有效载荷示例
<a name="binary-payloads-examples"></a>

当您使用 \$1 将消息有效载荷作为原始二进制数据进行引用时，您可以向规则添加数据。如果您有空的或 JSON 有效载荷，生成的有效载荷可以使用规则添加数据。下面显示了支持 `SELECT` 子句的示例。
+ 对于二进制有效载荷，您可以将以下 `SELECT` 子句仅与 \$1 一起使用。
  + 

    ```
    SELECT * FROM 'topic/subtopic'
    ```
  + 

    ```
    SELECT * FROM 'topic/subtopic' WHERE timestamp() % 12 = 0
    ```
+ 您还可以添加数据并使用以下 `SELECT` 子句。
  + 

    ```
    SELECT *, principal() as principal, timestamp() as time FROM 'topic/subtopic'
    ```
  + 

    ```
    SELECT encode(*, 'base64') AS data, timestamp() AS ts FROM 'topic/subtopic'
    ```
+ 您还可以使用带二进制有效载荷的 `SELECT` 子句。
  + 以下是指在 WHERE 子句中的 `device_type`。

    ```
    SELECT * FROM 'topic/subtopic' WHERE device_type = 'thermostat'
    ```
  + 还支持以下内容。

    ```
    {
    	"sql": "SELECT * FROM 'topic/subtopic'",
    	"actions": [
    		{
    			"republish": {
    				"topic": "device/${device_id}"
    			}
    		}
    	]
    }
    ```

以下规则操作不支持二进制有效载荷，因此您必须对它们进行解码。
+ 一些规则操作不支持二进制有效载荷输入（例如，[Lambda 操作](https://docs.aws.amazon.com/iot/latest/developerguide/iot-rule-actions.html#lambda-rule)），您必须解码二进制有效载荷。如果 Lambda 规则操作是 base64 编码并在 JSON 有效载荷中，则可以接收二进制数据。为此，您可以将规则更改如下：

  ```
  SELECT encode(*, 'base64') AS data FROM 'my_topic'
  ```
+ SQL 语句不支持字符串作为输入。要将字符串输入转换为 JSON，您可以运行以下命令。

  ```
  SELECT decode(encode(*, 'base64'), 'base64') AS payload FROM 'topic'
  ```

## 解码 protobuf 消息有效载荷
<a name="binary-payloads-protobuf"></a>

[协议缓冲区（protobuf）](https://developers.google.com/protocol-buffers) 是一种开源数据格式，用于以紧凑的二进制形式序列化结构化数据。它用于通过网络传输数据或将数据存储在文件中。Protobuf 允许您以比其他消息格式更快的速度以较小的数据包大小发送数据。 AWS IoT Core 规则通过提供[解码（值，decodingScheme）](iot-sql-functions.md#iot-sql-decode-base64)SQL 函数来支持 protobuf，该函数允许您将由 protobuf 编码的消息负载解码为 JSON 格式并将其路由到下游服务。本节详细介绍了在 “规则” 中配置 protobuf 解码的 step-by-step过程。 AWS IoT Core 

**Topics**
+ [

### 先决条件
](#binary-payloads-protobuf-prerequisites)
+ [

### 创建描述符文件
](#binary-payloads-protobuf-descriptor-steps)
+ [

### 将描述符文件上传到 S3 存储桶
](#binary-payloads-protobuf-s3-steps)
+ [

### 在规则中配置 protobuf 解码
](#binary-payloads-protobuf-steps)
+ [

### 限制
](#binary-payloads-protobuf-limitations)
+ [

### 最佳实践
](#binary-payloads-protobuf-bestpractices)

### 先决条件
<a name="binary-payloads-protobuf-prerequisites"></a>
+ 对[协议缓冲区（protobuf）](https://developers.google.com/protocol-buffers) 有基本的了解
+ 定义消息类型和相关依赖项的 [`.proto` 文件](https://developers.google.com/protocol-buffers/docs/proto3)
+ 在您的系统上安装 [Protobuf 编译器（protoc）](https://github.com/protocolbuffers/protobuf/releases)

### 创建描述符文件
<a name="binary-payloads-protobuf-descriptor-steps"></a>

如果您已有描述符文件，可以跳过此步骤。描述符文件 (`.desc`) 是 `.proto` 文件的编译版本，它是一个文本文件，用于定义 protobuf 序列化中使用的数据结构和消息类型。要生成描述符文件，必须定义一个 `.proto` 文件，并使用 [protoc](https://github.com/protocolbuffers/protobuf/releases) 编译器对其进行编译。

1. 创建定义消息类型的 `.proto` 文件。示例 `.proto` 文件可能如下所示：

   ```
   syntax = "proto3";
   
   message Person {
     optional string name = 1;
     optional int32 id = 2;
     optional string email = 3;
   }
   ```

   在此示例 `.proto` 文件中，使用 proto3 语法并定义消息类型 `Person`。`Person` 消息定义指定三个字段（名称、ID 和电子邮件）。有关 `.proto` 文件消息格式的更多信息，请参阅[语言指南（proto3）](https://developers.google.com/protocol-buffers/docs/proto3)。

1. 使用 [protoc](https://github.com/protocolbuffers/protobuf/releases) 编译器编译 `.proto` 文件并生成一个描述符文件。创建描述符 (`.desc`) 文件的示例命令如下所示：

   ```
   protoc --descriptor_set_out=<FILENAME>.desc \
       --proto_path=<PATH_TO_IMPORTS_DIRECTORY> \
       --include_imports \
       <PROTO_FILENAME>.proto
   ```

   此示例命令生成一个描述符文件`<FILENAME>.desc`， AWS IoT Core 规则可以使用该文件来解码符合中定义的数据结构的 protobuf 有效负载。`<PROTO_FILENAME>.proto`
   + `--descriptor_set_out`

     指定应生成的描述符文件 (`<FILENAME>.desc`) 的名称。
   + `--proto_path`

     指定正在编译的文件所引用的任何导入的 `.proto` 文件的位置。如果您有多个位于不同位置的已导入 `.proto` 文件，可以多次指定此标志。
   + `--include_imports`

     指定还应编译任何已导入的 `.proto` 文件，并将其包含在 `<FILENAME>.desc` 描述符文件中。
   + `<PROTO_FILENAME>.proto`

     指定要编译的 `.proto` 文件的名称。

   有关 protoc 参考的更多信息，请参阅 [API 参考](https://developers.google.com/protocol-buffers/docs/reference/overview)。

### 将描述符文件上传到 S3 存储桶
<a name="binary-payloads-protobuf-s3-steps"></a>

创建描述符文件后，使用 AWS API `<FILENAME>.desc`、S AWS DK 或，`<FILENAME>.desc`将描述符文件上传到 Amazon S3 存储桶。 AWS 管理控制台

**重要注意事项**
+ 请务必将描述符文件上传到您的 Amazon S3 存储桶，与您打算配置规则的 AWS 区域 位置相同。 AWS 账户 
+ 请确保您授予`FileDescriptorSet`从 S3 读取的 AWS IoT Core 权限。如果您的 S3 存储桶已禁用服务器端加密（SSE），或者 S3 存储桶已使用 Amazon S3 托管密钥（SSE-S3）加密，则不需要进行额外的策略配置。这可以通过示例存储桶策略来实现：  
****  

  ```
  {
  	"Version":"2012-10-17",		 	 	 
  	"Statement": [
  		{
  			"Sid": "Statement1",
  			"Effect": "Allow",
  			"Principal": {
  				"Service": "iot.amazonaws.com"
  			},
  			"Action": "s3:Get*",
                        "Resource": "arn:aws:s3:::<BUCKET NAME>/<FILENAME>.desc"
  		}
  	]
  }
  ```
+ 如果您的 S3 存储桶使用 AWS Key Management Service 密钥 (SSE-KMS) 进行加密，请确保授予在访问 S3 存储桶时使用该密钥的 AWS IoT Core 权限。这可以通过将此语句添加到密钥策略中来实现。

  ```
  {
  	"Sid": "Statement1",
  	"Effect": "Allow",
  	"Principal": {
  		"Service": "iot.amazonaws.com"
  	},
  	"Action": [
  		"kms:Decrypt",
  		"kms:GenerateDataKey*",
  		"kms:DescribeKey"
  	],
          "Resource": "arn:aws:kms:us-west-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab"
  	
  }
  ```

### 在规则中配置 protobuf 解码
<a name="binary-payloads-protobuf-steps"></a>

将描述符文件上传到 Amazon S3 桶后，配置一条[规则](https://docs.aws.amazon.com//iot/latest/developerguide/iot-create-rule.html)，该规则可以使用 [decode(value, decodingScheme)](iot-sql-functions.md#iot-sql-decode-base64) SQL 函数解码您的 protobuf 消息有效载荷格式。详细的函数签名和示例可以在《AWS IoT SQL 参考》**的 [decode(value, decodingScheme)](iot-sql-functions.md#iot-sql-decode-base64) SQL 函数中找到。

下面是使用 [decode(value, decodingScheme)](iot-sql-functions.md#iot-sql-decode-base64) 函数的 SQL 表达式示例：

```
SELECT VALUE decode(*, 'proto', '<BUCKET NAME>', '<FILENAME>.desc', '<PROTO_FILENAME>', '<PROTO_MESSAGE_TYPE>') FROM '<MY_TOPIC>'
```

在此示例表达式中：
+ 您可以使用 [decode(value, decodingScheme)](iot-sql-functions.md#iot-sql-decode-base64) SQL 函数来解码 `*` 引用的二进制消息有效载荷。这可以是 protobuf 编码的二进制有效载荷，也可以是表示 base64 编码的 protobuf 有效载荷的 JSON 字符串。
+ 提供的消息有效载荷使用中 `PROTO_FILENAME.proto` 定义的 `Person` 消息类型进行编码。
+ 名为 `BUCKET NAME` 的 Amazon S3 桶中包含从 `PROTO_FILENAME.proto` 生成的 `FILENAME.desc`。

完成配置后，向发布一条 AWS IoT Core 有关订阅该规则的主题的消息。

### 限制
<a name="binary-payloads-protobuf-limitations"></a>

AWS IoT Core 规则支持 protobuf，但有以下限制：
+ 不支持在[替换模板](https://docs.aws.amazon.com//iot/latest/developerguide/iot-substitution-templates.html)中解码 protobuf 消息有效载荷。
+ 解码 protobuf 消息有效载荷时，可以在单个 SQL 表达式中使用[解码 SQL 函数](iot-sql-functions.md#iot-sql-decode-base64)多达 2 次。
+ 最大入站有效载荷大小为 128 KiB（1KiB = 1024 字节），最大出站有效载荷大小为 128 KiB，存储在 Amazon S3 存储桶中的 `FileDescriptorSet` 对象的最大大小为 32 KiB。
+ 不支持使用 SSE-C 加密进行加密的 Amazon S3 存储桶。

### 最佳实践
<a name="binary-payloads-protobuf-bestpractices"></a>

以下是一些最佳实践和故障排除提示。
+ 在 Amazon S3 存储桶中备份您的原型文件。

  备份您的原型文件是一种很好的做法，以防出现问题。例如，如果您在运行 protoc 时错误地修改了没有备份的原型文件，这可能会导致您的生产堆栈出现问题。有多种方法可以在 Amazon S3 存储桶中备份您的文件。例如，您可以[在 S3 存储桶中使用版本控制](https://docs.aws.amazon.com//AmazonS3/latest/userguide/Versioning.html)。有关如何备份 Amazon S3 存储桶中的文件的更多信息，请参阅 *[Amazon S3 开发人员指南](https://docs.aws.amazon.com//aws-backup/latest/devguide/recovery-points.html)*。
+ 配置 AWS IoT 日志以查看日志条目。

  最好配置 AWS IoT 日志记录，这样你就可以在中查看账户的 AWS IoT 日志 CloudWatch。当规则的 SQL 查询调用外部函数时， AWS IoT Core Rules 会生成一个带为`eventType`的日志条目`FunctionExecution`，其中包含可帮助您排除故障原因字段。可能的错误包括找不到 Amazon S3 对象，或者 protobuf 文件描述符无效。有关如何配置 AWS IoT 日志记录和查看日志条目的更多信息，请参阅[配置 AWS IoT 日志记录](https://docs.aws.amazon.com//iot/latest/developerguide/configure-logging.html)和[规则引擎日志条目](https://docs.aws.amazon.com//iot/latest/developerguide/cwl-format.html#log-rules-fn-exec)。
+ 使用新的对象键更新 `FileDescriptorSet`，并更新规则中的对象键。

  您可以通过将更新后的描述符文件上传到 Amazon S3 桶来更新 `FileDescriptorSet`。您对 `FileDescriptorSet` 的更新最多需要 15 分钟能够反映出来。为了避免这一延迟，使用新的对象键上传更新后的 `FileDescriptorSet`，然后更新规则中的此对象密钥是一种很好的做法。