如何解析嵌套的 EventGrid 消息?

问题描述

我刚刚了解了由队列存储事件处理程序触发的 Azure 函数在这种情况下,队列存储正在处理事件网格消息。

问题:如何使用 Python 访问嵌套在下面 "body" 中的各种值?

  • 比如body/data/blobUrl的值

队列存储消息如下所示(缩进以便于阅读):

  • "body" 是嵌套的 EventGrid 消息
{
    "id": "<big-long-guid>","body": "{
        \"topic\":\"/subscriptions/<big-long-guid>/resourceGroups/azureStorage/providers/Microsoft.Storage/storageAccounts/stgcool\",\"subject\":\"/blobServices/default/containers/cont-pics/blobs/profile_pic.jpg\",\"eventType\":\"Microsoft.Storage.BlobCreated\",\"id\":\"<big-long-guid>\",\"data\":{
            \"api\":\"PutBlob\",\"clientRequestId\":\"<big-long-guid>\",\"requestId\":\"<big-long-guid>\",\"eTag\":\"0x8D94CE0B2F5CD71\",\"contentType\":\"image/jpeg\",\"contentLength\":35799,\"blobType\":\"BlockBlob\",\"blobUrl\":\"https://stgcool.blob.core.windows.net/cont-pics/profile_pic.jpg\",\"url\":\"https://stgcool.blob.core.windows.net/cont-pics/profile_pic.jpg\",\"sequencer\":\"00000000000000000000000000003730000000000000312a\",\"storageDiagnostics\":{
                \"batchId\":\"<big-long-guid>\"
            }
        },\"dataVersion\":\"\",\"MetadataVersion\":\"1\",\"eventTime\":\"2021-07-22T07:17:00.8479184Z\"
    }","expiration_time": "2021-07-30T05:10:37+00:00","insertion_time": "2021-07-23T05:10:37+00:00","time_next_visible": "2021-07-23T05:20:37+00:00","pop_receipt": "cOQ8m5lN2QgBAAAA","dequeue_count": 1
}

以下是生成上述日志的示例函数代码

import logging
import json

import azure.functions as func

def main(msg: func.QueueMessage):
    logging.info('Python queue trigger function processed a queue item.')

    result = json.dumps({
        'id': msg.id,'body': msg.get_body().decode('utf-8'),'expiration_time': (msg.expiration_time.isoformat()
                            if msg.expiration_time else None),'insertion_time': (msg.insertion_time.isoformat()
                           if msg.insertion_time else None),'time_next_visible': (msg.time_next_visible.isoformat()
                              if msg.time_next_visible else None),'pop_receipt': msg.pop_receipt,'dequeue_count': msg.dequeue_count
    })

    logging.info(result)

尝试过:

  • msg.get_body()get_json() 的不同迭代中包装 json.dumps(),但收到错误

编辑 1:

  • 'body': msg.get_body().decode('utf-8'), 更改为 'body': json.loads(msg.get_body().decode('utf-8')), 会将正文转换为实际的 JSON,这很好。

  • 但是我如何访问 ['body']['data']['blobUrl'] in result`?

  • type(result)str

解决方法

我写这篇文章的目的是理解您正在尝试更新您为 result 提供 logging 的方式。如果您真正想做的是从构造不佳的 Queue Storage 消息中解析它,请告诉我。

以你给出的字典为例:

d = {
    "id": "<big-long-guid>","body": "{
        \"topic\":\"/subscriptions/<big-long-guid>/resourceGroups/azureStorage/providers/Microsoft.Storage/storageAccounts/stgcool\",\"subject\":\"/blobServices/default/containers/cont-pics/blobs/profile_pic.jpg\",\"eventType\":\"Microsoft.Storage.BlobCreated\",\"id\":\"<big-long-guid>\",\"data\":{
            \"api\":\"PutBlob\",\"clientRequestId\":\"<big-long-guid>\",\"requestId\":\"<big-long-guid>\",\"eTag\":\"0x8D94CE0B2F5CD71\",\"contentType\":\"image/jpeg\",\"contentLength\":35799,\"blobType\":\"BlockBlob\",\"blobUrl\":\"https://stgcool.blob.core.windows.net/cont-pics/profile_pic.jpg\",\"url\":\"https://stgcool.blob.core.windows.net/cont-pics/profile_pic.jpg\",\"sequencer\":\"00000000000000000000000000003730000000000000312a\",\"storageDiagnostics\":{
                \"batchId\":\"<big-long-guid>\"
            }
        }",\"dataVersion\":\"\",\"metadataVersion\":\"1\",\"eventTime\":\"2021-07-22T07:17:00.8479184Z\"
    }","expiration_time": "2021-07-30T05:10:37+00:00","insertion_time": "2021-07-23T05:10:37+00:00","time_next_visible": "2021-07-23T05:20:37+00:00","pop_receipt": "cOQ8m5lN2QgBAAAA","dequeue_count": 1
}

我们可以这样查看 "body" 中的值:

d['body']['data']['api']
PutBlob

不幸的是,如果您尝试这样做,您会因为尝试使用 TypeError 尝试访问另一个 string 中的索引而向您抛出 string。我们使用 string 对象作为 dict 的键,而不是 string 的索引。您被抛出此类错误的原因是 "body" "dict" 实际上是 str,而不是 dict(注意 "花括号的两边)。

通过更新 json.dumps'body' 来解决此问题:

    result = json.dumps({
        'id': msg.id,'body': json.loads(msg.get_body().decode('utf-8')),...

编辑:

重新阅读您的问题,似乎我在您的示例中称为 dict 的内容在您得到它时可能仍然是一个字符串。在这种情况下,您可能会因为 "body" 的格式不正确而遇到更多问题。

如果是这种情况,您可以通过运行以下命令清除 " 值周围那些讨厌的 "body" 标记:

message = message.replace('"{','{').replace('}"','}')

在阅读之前:

d = json.loads(message)