Események fogadása HTTP-végponton

Ez a cikk azt ismerteti, hogyan érvényesíthet HTTP-végpontot események fogadásához egy esemény-előfizetésből, majd hogyan fogadhatja és deszerializálhatja az eseményeket. Ez a cikk egy Azure-függvényt használ bemutató célokra, de ugyanazok a fogalmak érvényesek, függetlenül attól, hogy hol üzemeltetik az alkalmazást.

Megjegyzés:

Azt javasoljuk, hogy egy Event Grid-eseményindítót használjon egy Azure-függvény Eseményrácskal való aktiválásához. Egyszerűbb és gyorsabb integrációt biztosít az Event Grid és az Azure Functions között. Vegye figyelembe azonban, hogy az Azure Functions Event Grid-eseményindítója nem támogatja azt a forgatókönyvet, amelyben az üzemeltetett kódnak szabályoznia kell az Event Gridnek visszaadott HTTP-állapotkódot. A korlátozás miatt az Azure-függvényen futó kód nem tud 5XX-ös hibát visszaadni például az Event Grid eseménykézbesítési újrapróbálkozásához.

Előfeltételek

HTTP-aktivált függvényt tartalmazó függvényalkalmazásra van szüksége.

Függőségek hozzáadása

Ha a .NET-ben fejleszt, adjon hozzá függőséget a Azure.Messaging.EventGridNuGet-csomaghoz tartozó függvényhez.

A más nyelvekhez készült SDK-k az SDK-k közzététele hivatkozáson keresztül érhetők el. Ezek a csomagok natív eseménytípusokhoz( például EventGridEvent, StorageBlobCreatedEventDataés EventHubCaptureFileCreatedEventData.

Végpont érvényesítése

Az első teendő az események kezelése Microsoft.EventGrid.SubscriptionValidationEvent . Minden alkalommal, amikor valaki előfizet egy eseményre, az Event Grid egy érvényesítési eseményt küld a végpontnak validationCode egy adat hasznos adattal. A végpontnak vissza kell adnia ezt a választörzsben, hogy igazolja, hogy a végpont érvényes és az Ön tulajdonában van. Ha a WebHook által aktivált függvény helyett Event Grid-eseményindítót használ, a rendszer a végpontérvényesítést kezeli. Ha külső API-szolgáltatást (például Zapier vagy IFTTT) használ, előfordulhat, hogy nem tudja programozott módon visszahangolni az érvényesítési kódot. Ezen szolgáltatások esetében manuálisan ellenőrizheti az előfizetést az előfizetés érvényesítési eseményében küldött érvényesítési URL-cím használatával. Másolja ki ezt az URL-címet a validationUrl tulajdonságban, és küldjön EGY GET kérést egy REST-ügyfélen vagy a webböngészőn keresztül.

A C#-ban a ParseMany() metódus egy vagy több eseményt tartalmazó példány deszerializálására BinaryDataEventGridEventszolgál. Ha előre tudta, hogy csak egyetlen eseményt deszerializál, használhatja helyette a metódust Parse .

Az érvényesítési kód programozott visszahangzásához használja az alábbi kódot.

using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using System;
using Azure.Messaging.EventGrid;
using Azure.Messaging.EventGrid.SystemEvents;

namespace Function1
{
    public static class Function1
    {
        [FunctionName("Function1")]
        public static async Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req,
            ILogger log)
        {
            log.LogInformation("C# HTTP trigger function processed a request.");
            string response = string.Empty;
            BinaryData events = await BinaryData.FromStreamAsync(req.Body);
            log.LogInformation($"Received events: {events}");

            EventGridEvent[] eventGridEvents = EventGridEvent.ParseMany(events);

            foreach (EventGridEvent eventGridEvent in eventGridEvents)
            {
                // Handle system events
                if (eventGridEvent.TryGetSystemEventData(out object eventData))
                {
                    // Handle the subscription validation event
                    if (eventData is SubscriptionValidationEventData subscriptionValidationEventData)
                    {
                        log.LogInformation($"Got SubscriptionValidation event data, validation code: {subscriptionValidationEventData.ValidationCode}, topic: {eventGridEvent.Topic}");
                        // Do any additional validation (as required) and then return back the below response
                        var responseData = new
                        {
                            ValidationResponse = subscriptionValidationEventData.ValidationCode
                        };

                        return new OkObjectResult(responseData);
                    }
                }
            }
            return new OkObjectResult(response);
        }
    }
}
module.exports = function (context, req) {
    context.log('JavaScript HTTP trigger function begun');
    var validationEventType = "Microsoft.EventGrid.SubscriptionValidationEvent";

    for (var events in req.body) {
        var body = req.body[events];
        // Deserialize the event data into the appropriate type based on event type
        if (body.data && body.eventType == validationEventType) {
            context.log("Got SubscriptionValidation event data, validation code: " + body.data.validationCode + " topic: " + body.topic);

            // Do any additional validation (as required) and then return back the below response
            var code = body.data.validationCode;
            context.res = { status: 200, body: { "ValidationResponse": code } };
        }
    }
    context.done();
};

Ellenőrzési válasz tesztelése

Tesztelje az érvényesítési válasz függvényt úgy, hogy beilleszti a mintaeseményt a függvény tesztmezőjére:

[{
  "id": "2d1781af-3a4c-4d7c-bd0c-e34b19da4e66",
  "topic": "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
  "subject": "",
  "data": {
    "validationCode": "512d38b6-c7b8-40c8-89fe-f46f9e9622b6"
  },
  "eventType": "Microsoft.EventGrid.SubscriptionValidationEvent",
  "eventTime": "2018-01-25T22:12:19.4556811Z",
  "metadataVersion": "1",
  "dataVersion": "1"
}]

Ha a Futtatás lehetőséget választja, a kimenetnek 200 OK-nak kell lennie, és {"validationResponse":"512d38b6-c7b8-40c8-89fe-f46f9e9622b6"} a törzsben:

Validation request

Validation output

Blob Storage-események kezelése

Most bővítsük ki a függvényt a Microsoft.Storage.BlobCreated rendszeresemény kezelésére:

using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using System;
using Azure.Messaging.EventGrid;
using Azure.Messaging.EventGrid.SystemEvents;

namespace Function1
{
    public static class Function1
    {
        [FunctionName("Function1")]
        public static async Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req,
            ILogger log)
        {
            log.LogInformation("C# HTTP trigger function processed a request.");
            string response = string.Empty;
            BinaryData events = await BinaryData.FromStreamAsync(req.Body);
            log.LogInformation($"Received events: {events}");

            EventGridEvent[] eventGridEvents = EventGridEvent.ParseMany(events);

            foreach (EventGridEvent eventGridEvent in eventGridEvents)
            {
                // Handle system events
                if (eventGridEvent.TryGetSystemEventData(out object eventData))
                {
                    // Handle the subscription validation event
                    if (eventData is SubscriptionValidationEventData subscriptionValidationEventData)
                    {
                        log.LogInformation($"Got SubscriptionValidation event data, validation code: {subscriptionValidationEventData.ValidationCode}, topic: {eventGridEvent.Topic}");
                        // Do any additional validation (as required) and then return back the below response

                        var responseData = new
                        {
                            ValidationResponse = subscriptionValidationEventData.ValidationCode
                        };
                        return new OkObjectResult(responseData);
                    }
                    // Handle the storage blob created event
                    else if (eventData is StorageBlobCreatedEventData storageBlobCreatedEventData)
                    {
                        log.LogInformation($"Got BlobCreated event data, blob URI {storageBlobCreatedEventData.Url}");
                    }
                }
            }
            return new OkObjectResult(response);
        }
    }
}
module.exports = function (context, req) {
    context.log('JavaScript HTTP trigger function begun');
    var validationEventType = "Microsoft.EventGrid.SubscriptionValidationEvent";
    var storageBlobCreatedEvent = "Microsoft.Storage.BlobCreated";

    for (var events in req.body) {
        var body = req.body[events];
        // Deserialize the event data into the appropriate type based on event type  
        if (body.data && body.eventType == validationEventType) {
            context.log("Got SubscriptionValidation event data, validation code: " + body.data.validationCode + " topic: " + body.topic);

            // Do any additional validation (as required) and then return back the below response
            var code = body.data.validationCode;
            context.res = { status: 200, body: { "ValidationResponse": code } };
        }

        else if (body.data && body.eventType == storageBlobCreatedEvent) {
            var blobCreatedEventData = body.data;
            context.log("Relaying received blob created event payload:" + JSON.stringify(blobCreatedEventData));
        }
    }
    context.done();
};

Blob által létrehozott eseménykezelés tesztelése

Tesztelje a függvény új funkcióit egy Blob Storage-esemény tesztmezőbe helyezésével és futtatásával:

[{
  "topic": "/subscriptions/{subscription-id}/resourceGroups/Storage/providers/Microsoft.Storage/storageAccounts/xstoretestaccount",
  "subject": "/blobServices/default/containers/testcontainer/blobs/testfile.txt",
  "eventType": "Microsoft.Storage.BlobCreated",
  "eventTime": "2017-06-26T18:41:00.9584103Z",
  "id": "831e1650-001e-001b-66ab-eeb76e069631",
  "data": {
    "api": "PutBlockList",
    "clientRequestId": "6d79dbfb-0e37-4fc4-981f-442c9ca65760",
    "requestId": "831e1650-001e-001b-66ab-eeb76e000000",
    "eTag": "0x8D4BCC2E4835CD0",
    "contentType": "text/plain",
    "contentLength": 524288,
    "blobType": "BlockBlob",
    "url": "https://example.blob.core.windows.net/testcontainer/testfile.txt",
    "sequencer": "00000000000004420000000000028963",
    "storageDiagnostics": {
      "batchId": "b68529f3-68cd-4744-baa4-3c0498ec19f0"
    }
  },
  "dataVersion": "",
  "metadataVersion": "1"
}]

A blob URL-kimenetének a függvénynaplóban kell megjelennie:

2022-11-14T22:40:45.978 [Information] Executing 'Function1' (Reason='This function was programmatically called via the host APIs.', Id=8429137d-9245-438c-8206-f9e85ef5dd61)
2022-11-14T22:40:46.012 [Information] C# HTTP trigger function processed a request.
2022-11-14T22:40:46.017 [Information] Received events: [{"topic": "/subscriptions/{subscription-id}/resourceGroups/Storage/providers/Microsoft.Storage/storageAccounts/xstoretestaccount","subject": "/blobServices/default/containers/testcontainer/blobs/testfile.txt","eventType": "Microsoft.Storage.BlobCreated","eventTime": "2017-06-26T18:41:00.9584103Z","id": "831e1650-001e-001b-66ab-eeb76e069631","data": {"api": "PutBlockList","clientRequestId": "6d79dbfb-0e37-4fc4-981f-442c9ca65760","requestId": "831e1650-001e-001b-66ab-eeb76e000000","eTag": "0x8D4BCC2E4835CD0","contentType": "text/plain","contentLength": 524288,"blobType": "BlockBlob","url": "https://example.blob.core.windows.net/testcontainer/testfile.txt","sequencer": "00000000000004420000000000028963","storageDiagnostics": {"batchId": "b68529f3-68cd-4744-baa4-3c0498ec19f0"}},"dataVersion": "","metadataVersion": "1"}]
2022-11-14T22:40:46.335 [Information] Got BlobCreated event data, blob URI https://example.blob.core.windows.net/testcontainer/testfile.txt
2022-11-14T22:40:46.346 [Information] Executed 'Function1' (Succeeded, Id=8429137d-9245-438c-8206-f9e85ef5dd61, Duration=387ms)

Azt is tesztelheti, hogy létrehoz egy Blob Storage-fiókot vagy egy általános célú V2 Storage-fiókot, hozzáad egy esemény-előfizetést, és beállítja a végpontot a függvény URL-címére:

Function URL

Egyéni események kezelése

Végül még egyszer bővítse ki a függvényt, hogy az egyéni eseményeket is kezelni tudja.

Ellenőrizze az eseményt Contoso.Items.ItemReceived. A végleges kódnak a következőképpen kell kinéznie:

using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using System;
using Azure.Messaging.EventGrid;
using Azure.Messaging.EventGrid.SystemEvents;

namespace Function1
{
    public static class Function1
    {
        [FunctionName("Function1")]
        public static async Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req,
            ILogger log)
        {
            log.LogInformation("C# HTTP trigger function processed a request.");
            string response = string.Empty;
            BinaryData events = await BinaryData.FromStreamAsync(req.Body);
            log.LogInformation($"Received events: {events}");

            EventGridEvent[] eventGridEvents = EventGridEvent.ParseMany(events);

            foreach (EventGridEvent eventGridEvent in eventGridEvents)
            {
                // Handle system events
                if (eventGridEvent.TryGetSystemEventData(out object eventData))
                {
                    // Handle the subscription validation event
                    if (eventData is SubscriptionValidationEventData subscriptionValidationEventData)
                    {
                        log.LogInformation($"Got SubscriptionValidation event data, validation code: {subscriptionValidationEventData.ValidationCode}, topic: {eventGridEvent.Topic}");
                        // Do any additional validation (as required) and then return back the below response

                        var responseData = new
                        {
                            ValidationResponse = subscriptionValidationEventData.ValidationCode
                        };
                        return new OkObjectResult(responseData);
                    }
                    // Handle the storage blob created event
                    else if (eventData is StorageBlobCreatedEventData storageBlobCreatedEventData)
                    {
                        log.LogInformation($"Got BlobCreated event data, blob URI {storageBlobCreatedEventData.Url}");
                    }
                }
                // Handle the custom contoso event
                else if (eventGridEvent.EventType == "Contoso.Items.ItemReceived")
                {
                    var contosoEventData = eventGridEvent.Data.ToObjectFromJson<ContosoItemReceivedEventData>();
                    log.LogInformation($"Got ContosoItemReceived event data, item SKU {contosoEventData.ItemSku}");
                }
            }
            return new OkObjectResult(response);
        }
    }
}
module.exports = function (context, req) {
    context.log('JavaScript HTTP trigger function begun');
    var validationEventType = "Microsoft.EventGrid.SubscriptionValidationEvent";
    var storageBlobCreatedEvent = "Microsoft.Storage.BlobCreated";
    var customEventType = "Contoso.Items.ItemReceived";

    for (var events in req.body) {
        var body = req.body[events];
        // Deserialize the event data into the appropriate type based on event type
        if (body.data && body.eventType == validationEventType) {
            context.log("Got SubscriptionValidation event data, validation code: " + body.data.validationCode + " topic: " + body.topic);

            // Do any additional validation (as required) and then return back the below response
            var code = body.data.validationCode;
            context.res = { status: 200, body: { "ValidationResponse": code } };
        }

        else if (body.data && body.eventType == storageBlobCreatedEvent) {
            var blobCreatedEventData = body.data;
            context.log("Relaying received blob created event payload:" + JSON.stringify(blobCreatedEventData));
        }

        else if (body.data && body.eventType == customEventType) {
            var payload = body.data;
            context.log("Relaying received custom payload:" + JSON.stringify(payload));
        }
    }
    context.done();
};

Egyéni eseménykezelés tesztelése

Végül tesztelje, hogy a függvény képes-e kezelni az egyéni eseménytípust:

[{
    "subject": "Contoso/foo/bar/items",
    "eventType": "Contoso.Items.ItemReceived",
    "eventTime": "2017-08-16T01:57:26.005121Z",
    "id": "602a88ef-0001-00e6-1233-1646070610ea",
    "data": { 
            "itemSku": "Standard"
            },
    "dataVersion": "",
    "metadataVersion": "1"
}]

Ezt a funkciót élőben is tesztelheti, ha egy egyéni eseményt küld a CURL-sel a portálról , vagy közzétesz egy egyéni témakört bármely olyan szolgáltatással vagy alkalmazással, amely postázható egy végponton, például a Postmanben. Hozzon létre egy egyéni témakört és egy esemény-előfizetést, amelynek végpontja függvény URL-címként van beállítva.

Üzenetfejlécek

Ezek a tulajdonságok jelennek meg az üzenetfejlécekben:

Tulajdonság neve Leírás
aeg-subscription-name Az esemény-előfizetés neve.
aeg-delivery-count Az eseményre tett kísérletek száma.
aeg-event-type

Az esemény típusa.

A következő értékek egyike lehet:

  • SubscriptionValidation
  • Értesítés
  • SubscriptionDeletion
aeg-metadata-version

Az esemény metaadat-verziója.

Az Event Grid eseményséma esetében ez a tulajdonság a metaadatok verzióját, a felhőbeli eseményséma esetében pedig a spec verziót jelöli.

aeg-data-version

Az esemény adatverziója.

Az Event Grid eseményséma esetében ez a tulajdonság az adatverziót jelöli, és a felhőbeli eseményséma esetében ez nem érvényes.

aeg-output-event-id Az Event Grid-esemény azonosítója.

További lépések