Slack の incoming webhook、curl で ok が返るのに通知が来ない
まとめ
- webhook への POST が
okでも、「自分が見ているチャンネルに届いた」保証はない。okは「どこかのチャンネルに投稿できた」の意味 - webhook URL 自体が、作成時に決めたデフォルトチャンネルを1つ持っている。payload の
channelはその上書き指定 channel上書きが効くのはレガシー型(custom integration)だけ。Slack App 型の webhook はチャンネル固定- 疎通テストの成功条件は「ok が返る」ではなく「見ているチャンネルにメッセージが出る」に置く
現象
Rails アプリの Slack 通知(slack-notifier gem)を staging で疎通確認していた。Rails コンソールからは届く。
Slack::Notifier.new(Settings.slack.webhook_url, channel: Settings.slack.channel).ping('test')
# => [#<Net::HTTPOK 200 OK readbody=true>]
# チャンネルに通知が出るところが同じ webhook URL に curl で投げると、レスポンスは ok なのにチャンネルには何も出ない。
curl -sS -X POST -H 'Content-Type: application/json' \
-d '{"text":"test"}' \
https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXX
# => ok (なのに通知が来ない)原因は payload の channel の有無
差分は JSON の channel フィールドだけだった。
slack-notifier は channel: オプションを payload に含めて {"channel":"my-app-staging","text":"test"} の形で送る。curl の方は {"text":"test"} だけ。
incoming webhook は URL 自体が「デフォルト投稿先チャンネル」を1つ持っている。webhook を作った人が作成時に選んだもので、payload に channel が無ければそこへ投稿され、あれば上書きされる。今回の webhook はデフォルトが別のチャンネルに向いていて、curl のメッセージはそっちに吸い込まれていた。Slack としては投稿に成功しているので、レスポンスは ok。
channel を足したら curl でも狙ったチャンネルに出た。
curl -sS -X POST -H 'Content-Type: application/json' \
-d '{"channel":"my-app-staging","text":"test"}' \
https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXchannel 上書きが効くのはレガシー型だけ
payload の channel で投稿先を切り替えられるのは、App ディレクトリの custom integration として作ったレガシー型 Incoming Webhook の挙動。現行の Slack App に紐づく webhook はチャンネル固定で、channel を入れても無視される。
手元の webhook がどちらか分からないときは、channel 付きで投げて実際に切り替わるかを見るのが早い。切り替わればレガシー型。デフォルトチャンネルの確認・変更は App ディレクトリの編集画面からできる(場所は slackのWebhookを一覧で確認したい に書いた)。
疎通テストの成功条件を HTTP 200 に置くと、今回のズレは見逃す。メッセージが実際に画面に出るところまで見て、初めて疎通確認と言える。webhook に限らず、レスポンスコードと「ユーザーから見えるところに出たか」は別物として扱った方がいい。