Skip to content

Webhook 通知(送信)の改修案 ​

第1版作成 最終更新 (日本時間)
確認バージョン1.5.8.1

プリザンターの通知には汎用の「HttpClient」種別があり、任意の URL に HTTP リクエストを送れます。ただし本文の組み立て方や認証の設定に制約があり、主要な SaaS の Webhook にそのまま送るには不便です。このページは、現行の HttpClient 通知の仕組みを確認したうえで、本体の標準機能ではない Webhook 通知種別を追加する改修案をまとめます。

HttpClient 通知の設定手順は Teams 通知・Asana タスク連携 を参照してください。

現行の HttpClient 通知(1.5.8.1) ​

通知種別とトリガー ​

通知種別は Mail(1)〜 LineWorks(10)で、HttpClient は 9 です(Notification.cs)。通知は次の操作で送られ、操作前・操作後の状態がビューの条件に合うか(BeforeCondition / AfterCondition と Expression)、指定した列が変わったか(MonitorChangesColumns)で絞れます(Notification.cs)。

プロパティタイミング
AfterCreate作成後
AfterUpdate更新後
AfterDelete削除後
AfterCopyコピー後
AfterBulkUpdate一括更新後
AfterBulkDelete一括削除後
AfterImportインポート後

リマインダーの種別には HttpClient がありません(Mail〜InCircle と LineWorks の 9 種。Reminder.cs)。

送信処理 ​

項目1.5.8.1 の動作
有効化Notification.json の HttpClient が true のときだけ送る。既定は false(Notification.cs、Notification.json)
メソッドGet / Post / Put / Delete。未設定なら Post(HttpClient.cs)
エンコード画面で選べるのは Notification.json の HttpClientEncodings(既定 utf-8 / shift_jis / euc-jp。NotificationUtilities.cs)
Content-Type既定 application/json(Notification.cs)
ヘッダHeaders に JSON の辞書で書く(例: {"Authorization":"Bearer xxx"})。送信時にデシリアライズしてリクエストヘッダに足す
非同期設定値の解釈(エンコード・ヘッダ・メソッド)だけ同期で行い、送信は Task.Run に投げる(HttpClient.cs)
失敗時例外を SysLogs に記録するだけ。再試行はしない
接続静的な System.Net.Http.HttpClient を 1 つ共有し、応答が 2xx 以外なら EnsureSuccessStatusCode で例外(NotificationHttpClient.cs)。タイムアウトは個別に設定しておらず、.NET の HttpClient の既定値のまま
トークン欄通知の「トークン」欄を使う種別は ChatWork・Line・LineGroup・InCircle だけで、HttpClient は対象外(NotificationUtilities.cs)

本文の組み立て ​

本文は NoticeBody が書式を改行で分割し、1 行ずつ処理して作ります(ResultModel.cs)。

  1. 各行を前後の空白を除いてから、列の書式({"Name":"[Title]"} のような NotificationColumnFormat の JSON)として読む
  2. 列が特定できた行は、その列の値(更新時は変更前後)に置き換える
  3. 列が特定できない行は、{Url}・{LoginId}・{UserName}・{MailAddress} の 4 つだけを置換して、そのまま出力する(ResultModel.cs)

既定の書式は {Url}、通知対象の各列の書式行、{UserName}<{MailAddress}> を改行でつないだものです(Notification.cs)。

このため、次のことができません。

  • 列の値は「行単位」で差し込まれるので、JSON の文字列の途中("text": "… [Title] …")に埋め込めない
  • [Title] のようなプレースホルダは、列の書式行以外では置換されない
  • 差し込んだ値は JSON 用にエスケープされない

サーバースクリプトから送る場合 ​

サーバースクリプトの notifications.New() が返すオブジェクトは MethodType・Encoding・MediaType・Headers を持たないため(ServerScriptModelNotificationModel.cs)、HttpClient 種別は使えません(詳しくは サーバースクリプトから生成 AI を使う)。サーバースクリプトからは httpClient を直接使います。httpClient は Get / Post / Put / Patch / Delete を持ち、タイムアウトは Script.json の ServerScriptHttpClientTimeOut(既定 100000 ミリ秒)です(ServerScriptModelHttpClient.cs、Script.cs)。

主要 SaaS の Webhook 仕様 ​

各サービスの仕様は調査時点のものです。

サービスURLContent-Type認証最小のペイロード
Slack Incoming Webhookshttps://hooks.slack.com/services/...application/jsonURL に秘密値を含む{"text":"…"}。リッチ表示は blocks 配列
Teams(Workflows / Power Automate)Power Automate が発行する URLapplication/jsonURL に SAS 署名任意の JSON(フロー側でカードに変換)
Discordhttps://discord.com/api/webhooks/{id}/{token}application/jsonURL に秘密値を含む{"content":"…"} または embeds 配列
Google Chathttps://chat.googleapis.com/v1/spaces/{space}/messages?key=…&token=…application/jsonURL にキー・トークン{"text":"…"}
Datadog Events APIhttps://api.datadoghq.com/api/v1/eventsapplication/jsonDD-API-KEY ヘッダ{"title":"…","text":"…"}
PagerDuty Events API v2https://events.pagerduty.com/v2/enqueueapplication/json本文の routing_keyevent_action と payload
認証方式例現行の HttpClient 通知
URL に秘密値を含むSlack、Discord、Google Chat、TeamsURL に書けば送れる
Bearer トークン各種 APIHeaders に手書きすれば送れる
独自名の API キーヘッダDatadog同上
本文に秘密値PagerDuty1 行の JSON に直接書けば送れる
Basic 認証社内ツールHeaders に Base64 を手書き
HMAC 署名受信側で署名を検証するサービス本文から毎回計算する必要があり、対応できない

改修案: Webhook 通知種別を追加する ​

既存の HttpClient 通知の設定項目を増やす案(影響は小さいが本文の制約が残る)と、新しい種別を追加する案を比べ、新しい種別 Webhook を追加する案を推奨します。用途と設定項目が違うので、画面と処理を分けたほうが既存の設定に影響しません。

変更箇所 ​

ファイル変更内容
Libraries/Settings/Notification.csTypes に Webhook = 11 を追加。認証方式・トークン・Basic 認証のユーザー名とパスワード・本文テンプレートの項目を追加し、Send に Webhook の分岐を追加
Libraries/Settings/NotificationUtilities.cs種別一覧に Webhook を追加(パラメータで有効なときだけ)
Models/Sites/SiteUtilities.cs通知の設定画面に認証方式の選択と、複数行の本文テンプレート欄を追加
ParameterAccessor/Parts/Notification.cs・App_Data/Parameters/Notification.jsonWebhook の有効・無効(既定 false)
App_Data/Displays/表示文字列 Webhook などを追加
csharp
public enum WebhookAuthTypes : int
{
    None = 0,         // URL に秘密値を含む
    BearerToken = 1,  // Authorization: Bearer {token}
    BasicAuth = 2,    // Authorization: Basic {base64(user:pass)}
    CustomHeader = 3  // 既存の Headers(JSON の辞書)をそのまま使う
}

private Dictionary<string, string> BuildAuthHeaders()
{
    var headers = Headers?.Deserialize<Dictionary<string, string>>()
        ?? new Dictionary<string, string>();
    switch (WebhookAuthType)
    {
        case WebhookAuthTypes.BearerToken:
            headers["Authorization"] = $"Bearer {WebhookAuthToken}";
            break;
        case WebhookAuthTypes.BasicAuth:
            var credentials = Convert.ToBase64String(
                System.Text.Encoding.UTF8.GetBytes($"{WebhookAuthUsername}:{WebhookAuthPassword}"));
            headers["Authorization"] = $"Basic {credentials}";
            break;
    }
    return headers;
}

本文テンプレート ​

NoticeBody の行単位の処理は使わず、テンプレート文字列全体に対して置換します。

  • [列名] は ss.IncludedColumns(template) で列を取り出し、表示値に置き換える(既存の ReplacedDisplayValues と同じ考え方。ResultModel.cs)
  • {Url}・{UserName} などのコンテキスト変数も置き換える
  • 値は JSON 文字列としてエスケープしてから埋め込む
  • テンプレートが空なら、従来の NoticeBody の結果を送る

図を読み込み中…

設定例 ​

送信先認証方式ヘッダ本文テンプレート
Slackなし―{"text": "[Title] が更新されました\n{Url}"}
Datadogカスタムヘッダ{"DD-API-KEY": "xxxxx"}{"title": "[Title]", "text": "[Body]", "alert_type": "info"}
PagerDutyなし―{"routing_key": "xxxxx", "event_action": "trigger", "payload": {"summary": "[Title]", "severity": "info", "source": "Pleasanter"}}

優先順位 ​

  1. Webhook 種別の追加(列挙値・パラメータ・画面)
  2. 本文テンプレートと複数行の入力欄
  3. 認証方式の選択(Bearer / Basic / カスタムヘッダ)

HMAC 署名は難度が高いため、この改修の対象外とします。

ほかに望まれる改善 ​

外部のフロー基盤(iPaaS 連携の実現可能性)の起点として使う場合は、次の改善も効きます。

項目現状改善案
再試行なし(送りっぱなし)指数バックオフで再試行する
送信ログ失敗時に SysLogs へ例外を記録するだけ成否と応答コードを履歴に残す
署名なしHMAC-SHA256 の署名ヘッダを付ける
流量制限なし宛先 URL ごとに制限する
タイムアウト個別設定なし通知ごとに設定する
失敗したペイロード残らない保存して再送できるようにする

関連ページ ​

変更履歴

第1版外部連携の改修・設計メモ(iCal・RSS/Atom・Webhook 送受信・iPaaS・短縮 URL・POP 受信・マスターデータ同期)を追加