Bolt for JavaScript でプロキシ内から Slack に接続する

4 min read 2

問題

Bolt for JavaScript を用いて Socket Mode の Slack App を作成したところ、プロキシ内で App を起動すると以下のようなメッセージが出て Slack に接続できませんでした。

[DEBUG]  web-api:WebClient:1 apiCall('apps.connections.open') start
[DEBUG]  web-api:WebClient:1 will perform http request
[WARN]  web-api:WebClient:0 http request failed getaddrinfo ENOTFOUND slack.com

環境変数 http_proxyhttps_proxy は設定してあって、wgetcurl は普通にプロキシ経由で接続できます。

結果

https-proxy-agent モジュールをインストールし、エージェントを作成して App 作成時に渡してやったところ App が正常に起動しました。

$ npm install https-proxy-agent
// 環境変数を読んでエージェントを作成
const HttpsProxyAgent = require('https-proxy-agent');
const proxy = process.env.https_proxy;
const agent = new HttpsProxyAgent(proxy);

const app = new App({
  logLevel: 'debug',
  socketMode: true,
  token: process.env.SLACK_BOT_TOKEN,
  appToken: process.env.SLACK_APP_TOKEN,
  agent  // エージェントを指定
});
[DEBUG]  web-api:WebClient:1 apiCall('apps.connections.open') start
[DEBUG]  web-api:WebClient:1 will perform http request
[DEBUG]  web-api:WebClient:1 http response received

疑問

(むしろこっちが本題)

  • ほんとに自分で書いてやらないといけないのか。
  • もっといい書き方はないか。
  • どこかのドキュメントに記載されているのか。

追記:Kazuhiro Seraさんのコメントですべて氷解しました!

詳細

Getting started with Bolt for JavaScript を見ながら Slack App を作ってみました。
自宅ではすんなり動いたのですが、プロキシ内で動かしてみたところ以下のようなメッセージが出て Slack に接続できません。

[DEBUG]  web-api:WebClient:1 apiCall('apps.connections.open') start
[DEBUG]  web-api:WebClient:1 will perform http request
[WARN]  web-api:WebClient:0 http request failed getaddrinfo ENOTFOUND slack.com

思い切りプロキシ周りな気がしますが何が悪いのかわかりません。環境変数 http_proxyhttps_proxy は設定してあって、wgetcurl は普通にプロキシ経由で接続できます。

同じ環境ですでに Slack App を作っている知り合いに聞いてみると、特に何もせずつながっているとのこと。
彼は Slack ソケットモードの最も簡単な始め方 - Qiita を見て始めたそうなのでこっちでもやってみますが同様です。

Bolt のソースを見てみました。App.js に気になるコメントを発見。

class App {
    constructor({ ... agent = undefined, ... } = {}) {
      ...
      this.axios = axios_1.default.create({
          httpAgent: agent,
          httpsAgent: agent,
          // disabling axios' automatic proxy support:
          // axios would read from envvars to configure a proxy automatically, but it doesn't support TLS destinations.
          // for compatibility with https://api.slack.com, and for a larger set of possible proxies (SOCKS or other
          // protocols), users of this package should use the `agent` option to configure a proxy.
          proxy: false,
          ...clientTls,
    });

axios の自動プロキシサポートを無効にしているから agent オプションを使いなさい、とな? そんなの聞いてないですよ?

ほんとかなあ・・・
いろんなプロキシをサポートできるように、って言っても環境変数読んで接続するくらいのところは作ってくれてていいような気がするんだけど・・・

まあ試しにやってみるか、とはいうもののエージェントって何状態から。
axios の README にはこんな記載がありました。

  // `httpAgent` and `httpsAgent` define a custom agent to be used when performing http
  // and https requests, respectively, in node.js. This allows options to be added like
  // `keepAlive` that are not enabled by default.
  httpAgent: new http.Agent({ keepAlive: true }),
  httpsAgent: new https.Agent({ keepAlive: true }),

芋づる式に http.Agent も見てみます。
HTTPのコネクションの取りまとめをしてくれるようなものらしい。
options を見ても残念ながらプロキシを指定するところはなさそうでした。

npm で検索してみたところ http-proxy-agent というのがありました。
これを使えばよさそう。

App 作るときに・・・こうかな?

const HttpsProxyAgent = require('https-proxy-agent');
const proxy = process.env.https_proxy;
const agent = new HttpsProxyAgent(proxy);

const app = new App({
  logLevel: 'debug',
  socketMode: true,
  token: process.env.SLACK_BOT_TOKEN,
  appToken: process.env.SLACK_APP_TOKEN,
  agent
});

うまくいくか・・・

[DEBUG]  web-api:WebClient:1 apiCall('apps.connections.open') start
[DEBUG]  web-api:WebClient:1 will perform http request
[DEBUG]  web-api:WebClient:1 http response received

起動しました!

しかしこれはどういうことでしょう。
探し方が悪いのか、Bolt のドキュメントでそれっぽいのが見つかりませんでした。
というか App クラスの説明すら見つからず。
ソース読みなさいってことでしょうか?

それとも Node.js 界隈では常識?
あるかもしれないけど、でも App オブジェクトのコンストラクタで指定するとかは常識の範囲ではないような。

特定のパッケージに依存しないように、ってことかもしれませんが axios にはがっつり依存してるわけだし。

Socket Mode ならファイアウォールの内側からでも接続できるよ、って
チュートリアルにもドヤ顔で(見えませんが)言ってるくらいですから
プロキシについてもひとこと触れてあってもいいと思うですが・・・

ということでもやっとが残る結果となりました。
知ってる方いたら教えてください!

Discussion

どうも、はじめまして。Bolt のメンテナーをしている者の一人です(日本にチームがあるわけではなく、日本から私だけがメンテナーに加わっております)。

どこかのドキュメントに記載されているのか。

ドキュメントに書いていあるのか?については、確かにわかりにくいかとは思うのですが、以下のドキュメントに記載はされております。

ほんとに自分で書いてやらないといけないのか。
もっといい書き方はないか。

この axios 側の設定をオフにしている点については、私が参画する以前よりも前からこうなっているため、そのまま互換性を維持していますが、将来のバージョンで見直すことがあるかもしれません。ですが、今日時点ではこの記事のように対応いただくことになります。

なお、Python と Java 版の Bolt やその内部で使っている SDK であれば http_proxy / https_proxy 環境変数が設定されている場合には何もコードに手を入れる必要がありません。ガイドを見て何もせずに動いたという同僚の方は Python か Java で実装されているのかもしれません。

Bolt について記事を書いていただき、ありがとうございました!

ありがとうございます!超すっきりです!
確かに動いてるひとはPythonでした!

ログインするとコメントできます