ウェブフックの使用
ウェブフックは、動画の処理が成功裏に完了し、ストリーミングの準備が整ったときや、動画がエラー状態に入ったときにサービスに通知します。
サービスでウェブフック通知を受け取るために購読するか、既存の購読を変更するには、Cloudflare APIトークン ↗が必要です。
ウェブフック通知のURLにはプロトコルを含める必要があります。http://またはhttps://のみがサポートされています。
curl -X PUT --header 'Authorization: Bearer <API_TOKEN>' \https://api.cloudflare.com/client/v4/accounts/<ACCOUNT_ID>/stream/webhook \--data '{"notificationUrl":"<WEBHOOK_NOTIFICATION_URL>"}'{ "result": { "notificationUrl": "http://www.your-service-webhook-handler.com", "modified": "2019-01-01T01:02:21.076571Z", "secret": "85011ed3a913c6ad5f9cf6c5573cc0a7" }, "success": true, "errors": [], "messages": []}アカウントの動画の処理が完了すると、動画に関する情報を含むPOSTリクエスト通知を受け取ります。
statusフィールドは、動画の処理が成功裏に完了したかどうかを示します。
{ "uid": "dd5d531a12de0c724bd1275a3b2bc9c6", "readyToStream": true, "status": { "state": "ready" }, "meta": {}, "created": "2019-01-01T01:00:00.474936Z", "modified": "2019-01-01T01:02:21.076571Z", // ... }動画の処理が完了し、すべての品質レベルがエンコードされると、stateフィールドはready状態を返します。ready状態は、画質が重要な場合に役立ち、最高品質のレベルが利用可能なときのみ動画再生を有効にしたい場合に便利です。
より高い品質のレンディションがまだ処理中の場合、動画は時折stateフィールドをreadyとして返し、pctComplete状態が100でないことがあります。pctCompleteが100に達すると、すべての品質解像度が動画に対して利用可能になります。
少なくとも1つの品質レベルがエンコードされ、ストリーミングの準備が整った場合、readyToStream値はtrueを返します。
動画が正常に処理できなかった場合、stateフィールドはerrorを返し、errReasonCodeは以下の値のいずれかを返します。
ERR_NON_VIDEO– アップロードは動画ではありません。ERR_DURATION_EXCEED_CONSTRAINT– 動画の長さが直接クリエイターアップロードで定義された制約を超えています。ERR_FETCH_ORIGIN_ERROR– 動画がURLからダウンロードできませんでした。ERR_MALFORMED_VIDEO– 動画は有効なファイルですが、回復できない破損データが含まれています。ERR_DURATION_TOO_SHORT– 動画の長さが0.1秒未満です。ERR_UNKNOWN– ストリームが動画がエラーを返した理由を自動的に特定できない場合、ERR_UNKNOWNコードが使用されます。
stateフィールドに加えて、動画が再生されるためには、動画のreadyToStreamフィールドもtrueでなければなりません。
{ "readyToStream": true, "status": { "state": "error", "step": "encoding", "pctComplete": "39", "errReasonCode": "ERR_MALFORMED_VIDEO", "errReasonText": "動画は破損または不正な形式と見なされました。", }}例: 成功した動画エンコーディングのPOSTボディ
{ "uid": "6b9e68b07dfee8cc2d116e4c51d6a957", "creator": null, "thumbnail": "https://customer-f33zs165nr7gyfy4.cloudflarestream.com/6b9e68b07dfee8cc2d116e4c51d6a957/thumbnails/thumbnail.jpg", "thumbnailTimestampPct": 0, "readyToStream": true, "status": { "state": "ready", "pctComplete": "39.000000", "errorReasonCode": "", "errorReasonText": "" }, "meta": { "filename": "small.mp4", "filetype": "video/mp4", "name": "small.mp4", "relativePath": "null", "type": "video/mp4" }, "created": "2022-06-30T17:53:12.512033Z", "modified": "2022-06-30T17:53:21.774299Z", "size": 383631, "preview": "https://customer-f33zs165nr7gyfy4.cloudflarestream.com/6b9e68b07dfee8cc2d116e4c51d6a957/watch", "allowedOrigins": [], "requireSignedURLs": false, "uploaded": "2022-06-30T17:53:12.511981Z", "uploadExpiry": "2022-07-01T17:53:12.511973Z", "maxSizeBytes": null, "maxDurationSeconds": null, "duration": 5.5, "input": { "width": 560, "height": 320 }, "playback": { "hls": "https://customer-f33zs165nr7gyfy4.cloudflarestream.com/6b9e68b07dfee8cc2d116e4c51d6a957/manifest/video.m3u8", "dash": "https://customer-f33zs165nr7gyfy4.cloudflarestream.com/6b9e68b07dfee8cc2d116e4c51d6a957/manifest/video.mpd" }, "watermark": null}Cloudflare Streamは、通知URLに送信されるウェブフックリクエストに署名し、各リクエストの署名をWebhook-Signature HTTPヘッダーに含めます。これにより、アプリケーションはウェブフックリクエストがStreamによって送信されたことを確認できます。
署名を確認するには、ウェブフック署名シークレットを取得する必要があります。この値は、ウェブフックを作成または取得する際にAPIレスポンスで返されます。
署名を確認するには、Webhook-Signatureヘッダーの値を取得します。これは以下の例のようになります。
Webhook-Signature: time=1230811200,sig1=60493ec9388b44585a29543bcf0de62e377d4da393246a8b1c901d0e3e672404
ウェブフックリクエストからWebhook-Signatureヘッダーを取得し、,文字を使用して文字列を分割します。
各値を=文字を使用して再度分割します。
timeの値は、サーバーがリクエストを送信したときの現在のUNIX時間 ↗です。sig1はリクエストボディの署名です。
この時点で、アプリケーションにとって古すぎるタイムスタンプのリクエストは破棄する必要があります。
署名ソース文字列を準備し、以下の文字列を連結します。
timeフィールドの値(例:1230811200)- 文字
. - ウェブフックリクエストボディ(改行文字を含む場合は完全に)
リクエストボディのすべてのバイトは、成功した署名検証のために変更されてはいけません。
ウェブフックシークレットとステップ2のソース文字列を使用して、SHA256関数(HMAC-SHA256)でHMACを計算します。 このステップは、アプリケーションで使用されるプログラミング言語に依存します。
Cloudflareの署名は16進数にエンコードされます。
リクエストヘッダーの署名を期待される署名と比較します。できれば、定数時間比較関数を使用して署名を比較してください。
署名が一致する場合、Cloudflareがウェブフックを送信したと信頼できます。
- ウェブフックは動画処理が完了した後にのみ送信され、ボディは動画処理が成功したか失敗したかを示します。
- アカウントごとに1つのウェブフック購読のみが許可されています。
Golang
crypto/hmac ↗を使用して:
package main
import ( "crypto/hmac" "crypto/sha256" "encoding/hex" "log")
func main() { secret := []byte("Cloudflare APIからのシークレット") message := []byte("ステップ2からの文字列")
hash := hmac.New(sha256.New, secret) hash.Write(message)
hashToCheck := hex.EncodeToString(hash.Sum(nil))
log.Println(hashToCheck)}Node.js
var crypto = require('crypto');
var key = 'Cloudflare APIからのシークレット'; var message = 'ステップ2からの文字列';
var hash = crypto.createHmac('sha256', key).update(message);
hash.digest('hex');Ruby
require 'openssl'
key = 'Cloudflare APIからのシークレット' message = 'ステップ2からの文字列'
OpenSSL::HMAC.hexdigest('sha256', key, message)JavaScript(例えば、Cloudflare Workersで使用するために)
const key = 'Cloudflare APIからのシークレット'; const message = 'ステップ2からの文字列';
const getUtf8Bytes = str => new Uint8Array( [...unescape(encodeURIComponent(str))].map(c => c.charCodeAt(0)) );
const keyBytes = getUtf8Bytes(key); const messageBytes = getUtf8Bytes(message);
const cryptoKey = await crypto.subtle.importKey( 'raw', keyBytes, { name: 'HMAC', hash: 'SHA-256' }, true, ['sign'] ); const sig = await crypto.subtle.sign('HMAC', cryptoKey, messageBytes);
[...new Uint8Array(sig)].map(b => b.toString(16).padStart(2, '0')).join('');