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. Ugyanezek a fogalmak érvényesek, függetlenül attól, hogy hol üzemeltetik az alkalmazást.
Feljegyzé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. Az Azure Functions Event Grid-eseményindítója azonban 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ényeken futó kód nem tud 5XX-os 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.EventGrid
NuGet-csomaghoz tartozó függvényhez.
A más nyelvekhez készült SDK-k a KözzétételI SDK-k referenciáján 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 BinaryData
EventGridEvent
szolgá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:
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": "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"
}]
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": "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)
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:
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égpontra. 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:
|
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. |