Menerima kejadian ke titik akhir HTTP
Artikel ini menjelaskan cara memvalidasi titik akhir HTTP untuk menerima kejadian dari Langganan Kejadian, lalu menerima dan mendeserialisasi kejadian. Artikel ini menggunakan Azure Function untuk tujuan demonstrasi. Namun konsep yang sama berlaku terlepas dari di mana aplikasi dihosting.
Catatan
Kami menyarankan agar Anda menggunakan Pemicu Event Grid saat memicu Azure Function dengan Event Grid. Ini memberikan integrasi yang lebih mudah dan lebih cepat antara Azure Event Grid dan Azure Functions. Namun pemicu Azure Functions Event Grid tidak mendukung skenario di mana kode yang dihosting perlu mengontrol kode status HTTP yang dikembalikan ke Event Grid. Mengingat batasan ini, kode Anda yang berjalan di Azure Function tidak akan dapat mengembalikan kesalahan 5XX untuk memulai coba lagi pengiriman peristiwa oleh Event Grid, misalnya.
Prasyarat
- Anda memerlukan aplikasi fungsi dengan fungsi yang dipicu HTTP.
Menambahkan dependensi
Jika Anda sedang mengembangkan di .NET, tambahkan dependensi ke fungsi Anda untuk Azure.Messaging.EventGrid
paket NuGet.
SDK untuk bahasa lain tersedia melalui referensi SDK Penerbitan. Paket ini memiliki model untuk jenis kejadian asli seperti EventGridEvent
, StorageBlobCreatedEventData
, dan EventHubCaptureFileCreatedEventData
.
Validasi titik akhir
Hal pertama yang ingin Anda lakukan adalah menangani kejadian Microsoft.EventGrid.SubscriptionValidationEvent
. Setiap kali seseorang berlangganan kejadian, Azure Event Grid mengirimkan kejadian validasi ke titik akhir dengan validationCode
di playload data. Titik akhir diperlukan untuk menggemakan ini kembali di isi tanggapan untuk membuktikan bahwa titik akhir tersebut valid dan milik Anda. Jika Anda menggunakan Pemicu Azure Event Grid daripada Fungsi yang dipicu WebHook, validasi titik akhir akan ditangani untuk Anda. Jika Anda menggunakan layanan API pihak ketiga (seperti Zapier atau IFTTT), Anda mungkin tidak dapat menggemakan kode validasi secara terprogram. Untuk layanan tersebut, Anda dapat memvalidasi langganan secara manual dengan menggunakan URL validasi yang dikirim dalam kejadian validasi langganan. Salin URL tersebut di properti validationUrl
dan kirim permintaan GET baik melalui klien REST atau browser web Anda.
Dalam C#, ParseMany()
metode ini digunakan untuk mendeserialisasi instans yang BinaryData
berisi satu atau beberapa peristiwa ke dalam array EventGridEvent
. Jika Anda tahu sebelumnya bahwa Anda hanya mendeserialisasi satu peristiwa, Anda dapat menggunakan metode sebagai gantinya Parse
.
Untuk menggemakan kode validasi secara terprogram, gunakan kode berikut.
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();
};
Menguji respons validasi
Uji fungsi respons validasi dengan menempelkan kejadian sampel ke dalam bidang pengujian untuk fungsi tersebut:
[{
"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"
}]
Saat Anda memilih Jalankan, Output harus 200 OK dan {"validationResponse":"512d38b6-c7b8-40c8-89fe-f46f9e9622b6"}
di isi:
Menangani kejadian penyimpanan Blob
Sekarang, mari kita perluas fungsi untuk menangani Microsoft.Storage.BlobCreated
peristiwa sistem:
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();
};
Menguji penanganan kejadian yang dibuat oleh Blob
Uji fungsionalitas baru dari fungsi tersebut dengan meletakkan kejadian penyimpanan Blob ke dalam bidang pengujian dan menjalankan:
[{
"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"
}]
Anda akan melihat output URL blob di log fungsi:
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)
Anda juga dapat menguji dengan membuat akun penyimpanan Blob atau akun Penyimpanan Tujuan Umum V2, menambahkan langganan peristiwa, dan mengatur titik akhir ke URL fungsi:
Menangani kejadian Khusus
Terakhir, mari perluas fungsi sekali lagi agar juga dapat menangani kejadian khusus.
Tambahkan cek untuk Contoso.Items.ItemReceived
kejadian Anda. Kode terakhir Anda akan terlihat seperti ini:
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();
};
Menguji penanganan kejadian khusus
Terakhir, uji apakah fungsi Anda sekarang dapat menangani jenis kejadian khusus Anda:
[{
"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"
}]
Anda juga dapat menguji fungsionalitas ini secara langsung dengan mengirim peristiwa kustom dengan CURL dari Portal atau dengan memposting ke topik kustom menggunakan layanan atau aplikasi apa pun yang dapat POST ke titik akhir. Buat topik khusus dan berlangganan kejadian dengan titik akhir yang diatur sebagai URL Fungsi.
Header pesan
Ini adalah properti yang Anda terima di header pesan:
Nama properti | Deskripsi |
---|---|
aeg-subscription-name | Nama langganan kejadian. |
aeg-delivery-count | Jumlah upaya yang dilakukan untuk kejadian. |
aeg-event-type | Jenis kejadian. Jenis dapat berupa salah satu dari nilai berikut:
|
aeg-metadata-version | Versi metadata kejadian. Untuk Skema kejadian Azure Event Grid, properti ini mewakili versi metadata dan untuk skema kejadian cloud, properti ini mewakili versi spesifikasi. |
aeg-data-version | Versi data kejadian. Untuk Skema kejadian Azure Event Grid, properti ini mewakili versi data dan untuk skema kejadian cloud, tidak berlaku. |
aeg-output-event-id | ID kejadian Azure Event Grid. |
Konten terkait
- Mempelajari Azure Event Grid Management dan Menerbitkan SDK
- Mempelajari cara memposting ke topik khusus