

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

# 使用自定义文件处理步骤
<a name="custom-step-details"></a>

通过使用自定义文件处理步骤，您可以使用 AWS Lambda自带文件处理逻辑。文件到达后，Transfer Family 服务器会调用包含自定义文件处理逻辑的 Lambda 函数，例如加密文件、扫描恶意软件或检查文件类型是否不正确。在以下示例中，目标 AWS Lambda 函数用于处理上一步的输出文件。

![\[自定义步骤屏幕，选中 “对根据上一步创建的文件应用自定义处理” 单选按钮，“目标” 字段中显示一个 Lambda 函数。\]](http://docs.aws.amazon.com/zh_cn/transfer/latest/userguide/images/workflows-step-custom.png)


**注意**  
有关示例 Lambda 函数，请参阅 [自定义工作流程步骤的 Lambda 函数示例](#example-workflow-lambda)。有关事件示例（包括传递到 Lambda 的文件的位置），请参阅 [文件上传 AWS Lambda 时发送到的事件示例](#example-workflow-lambdas)。

使用自定义工作流程步骤，您必须配置 Lambda 函数以调用 [SendWorkflowStepState](https://docs.aws.amazon.com/transfer/latest/APIReference/API_SendWorkflowStepState.html)API 操作。 `SendWorkflowStepState`通知工作流程执行该步骤已完成，状态为成功或失败。`SendWorkflowStepState` API 操作的状态根据 Lambda 函数的结果调用异常处理程序步骤或线性序列中的标称步骤。

如果 Lambda 函数失败或超时，则该步骤将失败，您将在日志`StepErrored`中看到。 CloudWatch 如果 Lambda 函数是标称步骤的一部分，并且函数响应 `SendWorkflowStepState` 为 `Status="FAILURE"` 或超时，则流程会继续执行异常处理程序步骤。在这种情况下，工作流不会继续执行剩余的（如果有）标称步骤。有关更多详细信息，请参阅[工作流程的异常处理](transfer-workflows.md#exception-workflow)。

在调用 `SendWorkflowStepState` API 操作时，必须发送以下参数：

```
{
    "ExecutionId": "string",
    "Status": "string",
    "Token": "string",
    "WorkflowId": "string"
}
```

您可以从 Lambda 函数执行时传递的输入事件中提取 `ExecutionId`、`Token` 和 `WorkflowId`（以下各节显示了示例）。该`Status`值可以是 `SUCCESS` 或`FAILURE`。

为了能够从 Lambda 函数调用 `SendWorkflowStepState` API 操作，您必须使用在引入[托管工作流程](doc-history.md#workflows-introduced)之后发布的 AWS SDK 版本。

## 连续使用多个 Lambda 函数
<a name="multiple-lambdas"></a>

当您依次使用多个自定义步骤时，“**文件位置**”选项的工作方式与仅使用单个自定义步骤时不同。Transfer Family 不支持传回 Lambda 处理过的文件以用作下一步的输入。因此，如果您将多个自定义步骤全部配置为使用 `previous.file` 选项，则它们都使用相同的文件位置（第一个自定义步骤的输入文件位置）。

**注意**  
如果您在自定义步骤之后有预定义的步骤（标记、复制、解密或删除），则 `previous.file` 设置的工作方式也会有所不同。如果将预定义步骤配置为使用 `previous.file` 设置，则预定义步骤将使用与自定义步骤相同的输入文件。来自自定义步骤的已处理文件不会传递到预定义的步骤。

## 在自定义处理后访问文件
<a name="process-uploaded-file"></a>

如果您使用 Amazon S3 作为存储，并且您的工作流程包括对最初上传的文件执行操作的自定义步骤，则后续步骤将无法访问该已处理的文件。也就是说，自定义步骤之后的任何步骤都不能从自定义步骤输出中引用更新的文件。

例如，假设您的工作流程中有以下三个步骤。
+ **步骤 1** - 上传名为 `example-file.txt` 的文件。
+ **步骤 2** - 调用以某种方式更改`example-file.txt`的 Lambda 函数。
+ **步骤 3** - 尝试对 `example-file.txt` 的更新版本执行进一步处理。

如果将步骤 3 的 `sourceFileLocation` 配置为 `${original.file}`，则步骤 3 将使用步骤 1 中服务器将文件上传到存储器时的原始文件位置。如果您在步骤 3 使用 `${previous.file}`，则步骤 3 会重复使用步骤 2 用作输入的文件位置。

因此，步骤 3 会导致错误。例如，如果步骤 3 尝试复制更新的 `example-file.txt`，则会收到以下错误：

```
{
    "type": "StepErrored",
    "details": {
        "errorType": "NOT_FOUND",
        "errorMessage": "ETag constraint not met (Service: null; Status Code: 412; Error Code: null; Request ID: null; S3 Extended Request ID: null; Proxy: null)",
        "stepType": "COPY",
        "stepName": "CopyFile"
    },
```

之所以出现此错误，是因为自定义步骤修改了的实体标签 (ETag)，`example-file.txt`使其与原始文件不匹配。

**注意**  
如果您使用的是 Amazon EFS，则不会发生这种情况，因为 Amazon EFS 不使用实体标签来识别文件。

## 文件上传 AWS Lambda 时发送到的事件示例
<a name="example-workflow-lambdas"></a>

以下示例显示了文件上传完成 AWS Lambda 时发送到的事件。一个示例使用 Transfer Family 服务器，其中域名配置了 Amazon S3。另一个示例使用 Transfer Family 服务器，其中域名使用 Amazon EFS。

------
#### [ Custom step that uses an Amazon S3 domain ]

```
{
    "token": "MzI0Nzc4ZDktMGRmMi00MjFhLTgxMjUtYWZmZmRmODNkYjc0",
    "serviceMetadata": {
        "executionDetails": {
            "workflowId": "w-1234567890example",
            "executionId": "abcd1234-aa11-bb22-cc33-abcdef123456"
        },
        "transferDetails": {
            "sessionId": "36688ff5d2deda8c",
            "userName": "myuser",
            "serverId": "s-example1234567890"
        }
    },
    "fileLocation": {
        "domain": "S3",
        "bucket": "amzn-s3-demo-bucket",
        "key": "path/to/mykey",
        "eTag": "d8e8fca2dc0f896fd7cb4cb0031ba249",
        "versionId": null
    }
}
```

------
#### [ Custom step that uses an Amazon EFS domain ]

```
{
    "token": "MTg0N2Y3N2UtNWI5Ny00ZmZlLTk5YTgtZTU3YzViYjllNmZm",
    "serviceMetadata": {
        "executionDetails": {
            "workflowId": "w-1234567890example",
            "executionId": "abcd1234-aa11-bb22-cc33-abcdef123456"
        },
        "transferDetails": {
            "sessionId": "36688ff5d2deda8c",
            "userName": "myuser",
            "serverId": "s-example1234567890"
        }
    },
    "fileLocation": {
        "domain": "EFS",
        "fileSystemId": "fs-1234567",
        "path": "/path/to/myfile"
    }
}
```

------

## 自定义工作流程步骤的 Lambda 函数示例
<a name="example-workflow-lambda"></a>

以下 Lambda 函数提取有关执行状态的信息，然后调用 [SendWorkflowStepState](https://docs.aws.amazon.com/transfer/latest/APIReference/API_SendWorkflowStepState.html)API 操作将该步骤`SUCCESS`的状态返回到工作流程，可以是或。`FAILURE`在您的函数调用 `SendWorkflowStepState` API 操作之前，您可以将 Lambda 配置为根据您的工作流程逻辑执行操作。

```
import json
import boto3

transfer = boto3.client('transfer')

def lambda_handler(event, context):
    print(json.dumps(event))

    # call the SendWorkflowStepState API to notify the workflow about the step's SUCCESS or FAILURE status
    response = transfer.send_workflow_step_state(
        WorkflowId=event['serviceMetadata']['executionDetails']['workflowId'],
        ExecutionId=event['serviceMetadata']['executionDetails']['executionId'],
        Token=event['token'],
        Status='SUCCESS|FAILURE'
    )

    print(json.dumps(response))

    return {
      'statusCode': 200,
      'body': json.dumps(response)
    }
```

## 自定义步骤的 IAM 权限
<a name="custom-step-iam"></a>

若要使调用 Lambda 的步骤成功，请确保您的工作流程的执行角色包含以下权限。

```
{
    "Sid": "Custom",
    "Effect": "Allow",
    "Action": [
        "lambda:InvokeFunction"
    ],
    "Resource": [
        "arn:aws:lambda:region:account-id:function:function-name"
    ]
}
```