Příjem událostí pro koncový bod HTTP
Tento článek popisuje, jak ověřit koncový bod HTTP pro příjem událostí z odběru událostí a následné přijímání a deserializaci událostí. Tento článek používá funkci Azure Functions pro demonstrační účely, ale stejné koncepty platí bez ohledu na to, kde je aplikace hostovaná.
Poznámka:
Při aktivaci funkce Azure Functions pomocí Event Gridu doporučujeme použít trigger služby Event Grid. Poskytuje snadnější a rychlejší integraci mezi Event Gridem a Azure Functions. Mějte ale na paměti, že trigger Event Gridu služby Azure Functions nepodporuje scénář, ve kterém hostovaný kód potřebuje řídit stavový kód HTTP vrácený do Event Gridu. Vzhledem k tomuto omezení by váš kód spuštěný ve funkci Azure Functions nemohl vrátit chybu 5XX, aby například inicioval opakování doručení události službou Event Grid.
Požadavky
Potřebujete aplikaci funkcí s funkcí aktivovanou protokolem HTTP.
Přidání závislostí
Pokud vyvíjíte v .NET, přidejte do své funkce závislost pro Azure.Messaging.EventGrid
balíček NuGet.
Sady SDK pro jiné jazyky jsou dostupné prostřednictvím referenčních informací k publikování sad SDK . Tyto balíčky mají modely pro nativní typy událostí, jako EventGridEvent
jsou , StorageBlobCreatedEventData
a EventHubCaptureFileCreatedEventData
.
Ověření koncového bodu
První věc, kterou chcete udělat, je zpracování Microsoft.EventGrid.SubscriptionValidationEvent
událostí. Pokaždé, když se někdo přihlásí k odběru události, event Grid odešle ověřovací událost do koncového bodu s datovou validationCode
částí. Koncový bod se musí vrátit zpět do textu odpovědi, aby prokázal, že koncový bod je platný a vlastníte ho. Pokud místo funkce aktivované webhookem používáte trigger Event Gridu, ověření koncového bodu se za vás zpracuje. Pokud používáte službu rozhraní API třetí strany (například Zapier nebo IFTTT), možná nebudete moct kód ověření opakovat prostřednictvím kódu programu. U těchto služeb můžete předplatné ručně ověřit pomocí ověřovací adresy URL, která se odešle v události ověření odběru. Zkopírujte adresu URL ve validationUrl
vlastnosti a odešlete požadavek GET prostřednictvím klienta REST nebo webového prohlížeče.
V jazyce C# se ParseMany()
metoda používá k deserializaci BinaryData
instance obsahující jednu nebo více událostí do pole EventGridEvent
. Pokud jste předem věděli, že deserializujete pouze jednu událost, můžete místo toho použít metodu Parse
.
Pokud chcete ověřovací kód opakovat prostřednictvím kódu programu, použijte následující kód.
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();
};
Odpověď na ověření testu
Otestujte funkci ověřovací odpovědi vložením ukázkové události do testovacího pole pro funkci:
[{
"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"
}]
Když vyberete Spustit, výstup by měl být 200 OK a {"validationResponse":"512d38b6-c7b8-40c8-89fe-f46f9e9622b6"}
v textu:
Zpracování událostí úložiště objektů blob
Teď funkci rozšíříme tak, aby zpracovávala Microsoft.Storage.BlobCreated
událost systému:
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();
};
Testování zpracování událostí vytvořených objektem blob
Otestujte novou funkci funkce vložením události úložiště objektů blob do testovacího pole a spuštěním:
[{
"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": "aaaa0a0a-bb1b-cc2c-dd3d-eeeeee4e4e4e",
"data": {
"api": "PutBlockList",
"clientRequestId": "bbbb1b1b-cc2c-dd3d-ee4e-ffffff5f5f5f",
"requestId": "cccc2c2c-dd3d-ee4e-ff5f-aaaaaa6a6a6a",
"eTag": "0x8D4BCC2E4835CD0",
"contentType": "text/plain",
"contentLength": 524288,
"blobType": "BlockBlob",
"url": "https://example.blob.core.windows.net/testcontainer/testfile.txt",
"sequencer": "00000000000004420000000000028963",
"storageDiagnostics": {
"batchId": "dddd3d3d-ee4e-ff5f-aa6a-bbbbbb7b7b7b"
}
},
"dataVersion": "",
"metadataVersion": "1"
}]
V protokolu funkcí by se měl zobrazit výstup adresy URL objektu blob:
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": "aaaa0a0a-bb1b-cc2c-dd3d-eeeeee4e4e4e","data": {"api": "PutBlockList","clientRequestId": "bbbb1b1b-cc2c-dd3d-ee4e-ffffff5f5f5f","requestId": "cccc2c2c-dd3d-ee4e-ff5f-aaaaaa6a6a6a","eTag": "0x8D4BCC2E4835CD0","contentType": "text/plain","contentLength": 524288,"blobType": "BlockBlob","url": "https://example.blob.core.windows.net/testcontainer/testfile.txt","sequencer": "00000000000004420000000000028963","storageDiagnostics": {"batchId": "dddd3d3d-ee4e-ff5f-aa6a-bbbbbb7b7b7b"}},"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)
Můžete také testovat tak, že vytvoříte účet úložiště blob nebo účet úložiště pro obecné účely V2, přidáte odběr události a nastavíte koncový bod na adresu URL funkce:
Zpracování vlastních událostí
Nakonec můžeme funkci rozšířit ještě jednou, aby mohl také zpracovávat vlastní události.
Přidejte kontrolu události Contoso.Items.ItemReceived
. Konečný kód by měl vypadat takto:
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();
};
Testování vlastního zpracování událostí
Nakonec otestujte, že vaše funkce teď dokáže zpracovat váš vlastní typ události:
[{
"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"
}]
Tuto funkci můžete také otestovat živě odesláním vlastní události pomocí nástroje CURL z portálu nebo publikováním do vlastního tématu pomocí libovolné služby nebo aplikace, která může odeslat příspěvek do koncového bodu. Vytvořte vlastní téma a odběr událostí s koncovým bodem nastaveným jako adresou URL funkce.
Záhlaví zpráv
Toto jsou vlastnosti, které obdržíte v záhlaví zprávy:
Název vlastnosti | Popis |
---|---|
aeg-subscription-name | Název odběru události. |
aeg-delivery-count | Počet pokusů o událost |
aeg-event-type | Typ události Může to být jedna z následujících hodnot:
|
aeg-metadata-version | Verze metadat události Pro schéma událostí Event Gridu tato vlastnost představuje verzi metadat a pro schéma cloudové události představuje verzi specifikace. |
aeg-data-version | Datová verze události U schématu událostí Event Gridu tato vlastnost představuje datovou verzi a pro schéma cloudové události se nepoužije. |
aeg-output-event-id | ID události Event Gridu. |
Další kroky
- Prozkoumání správy a publikování sad SDK služby Azure Event Grid
- Přečtěte si, jak publikovat vlastní téma.