Skip Navigation
Show nav
Heroku Dev Center
  • Get Started
  • ドキュメント
  • Changelog
  • Search
  • Get Started
    • Node.js
    • Ruby on Rails
    • Ruby
    • Python
    • Java
    • PHP
    • Go
    • Scala
    • Clojure
  • ドキュメント
  • Changelog
  • More
    Additional Resources
    • Home
    • Elements
    • Products
    • Pricing
    • Careers
    • Help
    • Status
    • Events
    • Podcasts
    • Compliance Center
    Heroku Blog

    Heroku Blog

    Find out what's new with Heroku on our blog.

    Visit Blog
  • Log inorSign up
View categories

Categories

  • Heroku のアーキテクチャ
    • Dyno (アプリコンテナ)
    • スタック (オペレーティングシステムイメージ)
    • ネットワーキングと DNS
    • プラットフォームポリシー
    • プラットフォームの原則
  • コマンドライン
  • デプロイ
    • Git を使用したデプロイ
    • Docker によるデプロイ
    • デプロイ統合
  • 継続的デリバリー
    • 継続的統合
  • 言語サポート
    • Node.js
    • Ruby
      • Bundler の使用
      • Rails のサポート
    • Python
      • Django の使用
      • Python でのバックグランドジョブ
    • Java
      • Maven の使用
      • Java でのデータベース操作
      • Play Framework の使用
      • Java の高度なトピック
      • Spring Boot の使用
    • PHP
    • Go
      • Go の依存関係管理
    • Scala
    • Clojure
  • データベースとデータ管理
    • Heroku Postgres
      • Postgres の基礎
      • Postgres Getting Started
      • Postgres のパフォーマンス
      • Postgres のデータ転送と保持
      • Postgres の可用性
      • Postgres の特別なトピック
    • Heroku Redis
    • Apache Kafka on Heroku
    • その他のデータストア
  • モニタリングとメトリクス
    • ログ記録
  • アプリのパフォーマンス
  • アドオン
    • すべてのアドオン
  • 共同作業
  • セキュリティ
    • アプリのセキュリティ
    • ID と認証
    • コンプライアンス
  • Heroku Enterprise
    • Private Space
      • インフラストラクチャネットワーキング
    • Enterprise Accounts
    • Enterprise Team
    • Heroku Connect (Salesforce 同期)
      • Heroku Connect の管理
      • Heroku Connect のリファレンス
      • Heroku Connect のトラブルシューティング
    • シングルサインオン (SSO)
  • パターンとベストプラクティス
  • Heroku の拡張
    • Platform API
    • アプリの Webhook
    • Heroku Labs
    • アドオンのビルド
      • アドオン開発のタスク
      • アドオン API
      • アドオンのガイドラインと要件
    • CLI プラグインのビルド
    • 開発ビルドパック
    • Dev Center
  • アカウントと請求
  • トラブルシューティングとサポート
  • Integrating with Salesforce
  • 言語サポート
  • Clojure
  • Clojure と Immutant で Heroku の WebSocket を使用する

Clojure と Immutant で Heroku の WebSocket を使用する

日本語 — Switch to English

最終更新日 2022年02月09日(水)

Table of Contents

  • 前提条件
  • WebSocket アプリの作成
  • 機能
  • アプリのローカル実行
  • Heroku へのアプリのデプロイ

このチュートリアルでは、WebSocket​ を使用する Immutant​ と共に Clojure アプリケーションを構築する方法について学びます。その後、アプリケーションを Heroku にデプロイする方法について学びます。

デモアプリケーション​のサンプルコードは GitHub で入手できます。編集や機能強化を歓迎します。単にリポジトリをフォークし、変更を加えて、プルリクエストを送信してください。

前提条件

  • Java、Leiningen、および Heroku CLI (Heroku CLI のセットアップに関する記事)​で説明しているとおり)
  • Heroku ユーザーアカウント。 無料ですぐにサインアップできます​。

WebSocket アプリの作成

次のように、Leiningen を足場にしてプロジェクトを生成することから始めます。

$ lein new demo
Generating a project called demo based on the 'default' template.
The default template is intended for library projects, not applications.
To see other templates (app, plugin, etc), try `lein help new`.

次に、Immutant の依存関係を project.clj​ ファイルに追加し、次の設定を追加して Immutant を Heroku 用に準備します。

(defproject demo "0.1.0-SNAPSHOT"
  :dependencies [[org.clojure/clojure "1.6.0"]
                  [org.immutant/web "2.0.0-beta2"]
                  [compojure "1.1.8"]
                  [ring/ring-core "1.3.0"]
                  [environ "1.0.0"]]
  :main demo.core
  :uberjar-name "demo-standalone.jar"
  :profiles {:uberjar {:aot [demo.core]}}
  :min-lein-version "2.4.0")

これで、アプリケーションに動作を追加する準備ができました。

機能

このサンプルアプリケーションは、バックエンドへの WebSocket を開く単純な Web ページをレンダリングします。クライアントは、文字列を含むペイロードを WebSocket 経由で送信します。サーバーは文字列を反転して、結果をクライアントに送り返します。

このやり取りには、2 つの重要な部分があります。サーバー側のコールバック関数と、WebSocket を開く JavaScript ファイルです。

サーバー

プロジェクトの src/demo/core.clj​ ファイルで、次の依存関係をファイルの先頭に追加します (既存の名前空間ステートメントを置き換えます)。

(ns demo.core
  (:require
    [immutant.web             :as web]
    [immutant.web.async       :as async]
    [immutant.web.middleware  :as web-middleware]
    [compojure.route          :as route]
    [environ.core             :refer (env)]
    [compojure.core           :refer (ANY GET defroutes)]
    [ring.util.response       :refer (response redirect content-type)])
  (:gen-class))

その後に、WebSocket コールバック関数を定義します。

(def websocket-callbacks
  "WebSocket callback functions"
  {:on-open   (fn [channel]
    (async/send! channel "Ready to reverse your messages!"))
  :on-close   (fn [channel {:keys [code reason]}]
    (println "close code:" code "reason:" reason))
  :on-message (fn [ch m]
    (async/send! ch (apply str (reverse m))))})

websocket-callbacks​ 関数では、3 つの関数のマップを定義します。これらの関数は、それぞれソケットを開く、ソケットを閉じる、メッセージを受信するために実行されます。

次に、アプリケーションの Web ルートを定義します。

(defroutes routes
  (GET "/" {c :context} (redirect (str c "/index.html")))
  (route/resources "/"))

最後に、アプリケーションへのエントリポイントとして main 関数を作成します。

(defn -main [& {:as args}]
  (web/run
    (-> routes
      (web-middleware/wrap-session {:timeout 20})
      ;; wrap the handler with websocket support
      ;; websocket requests will go to the callbacks, ring requests to the handler
      (web-middleware/wrap-websocket websocket-callbacks))
      (merge {"host" (env :demo-web-host), "port" (env :demo-web-port)}
      args)))

サーバー側では、クライアントからのメッセージを処理する準備ができています。

クライアント

クライアント側では、単純な HTML ページを使用してデモを制御します。resources/public/index.html​ ファイルを作成し、その中に次のコードを記述します。

<html>
<head>
  <meta charset="utf-8">
  <title>WebSocket Demo</title>
</head>
<body>
  <h1>WebSocket Demo</h1>
  <div>
    <input type="text" id="input" value="Enter text to reverse!" />
  </div>
  <div>
    <button type="button" id="open">Open</button>
    <button type="button" id="send">Send</button>
    <button type="button" id="close">Close</button>
  </div>
  <div id="messages"></div>
  <script src="js/app.js"></script>
</body>
</html>

このページにはテキストボックス、開くボタン、送信ボタン、閉じるボタン、一部のメッセージ用の領域があります。しかし、これらはまだ機能しません。これらに動作を追加するには、何らかの JavaScript が必要になります。resources/public/js/app.js​ ファイルを作成し、その中に次のコードを記述します。

window.onload = function() {
  var input = document.getElementById('input');
  var openBtn = document.getElementById('open');
  var sendBtn = document.getElementById('send');
  var closeBtn = document.getElementById('close');
  var messages = document.getElementById('messages');

  var socket;
};

これにより、window.onload​ 関数が定義されます。また、テキストボックスの内容、ボタン、メッセージ領域、通信に使用するソケットを表す変数も定義されます。

次に、window.onload​ の本体に、messages​ 変数を更新するための関数 (関数内の関数) を追加します。

function output(style, text){
  messages.innerHTML += "<br/><span class='" + style + "'>" + text + "</span>";
}

これは、ソケットと通信するときにコールバックとして使用されます。この関数の後 (ただし、まだ window.onload​ 関数の内側) に次のコードを追加して、開くボタンの動作を定義します。

openBtn.onclick = function(e) {
  e.preventDefault();
  if (socket !== undefined) {
    output("error", "Already connected");
    return;
  }

  var uri = "ws://" + location.host + location.pathname;
  uri = uri.substring(0, uri.lastIndexOf('/'));
  socket = new WebSocket(uri);

  socket.onerror = function(error) {
    output("error", error);
  };

  socket.onopen = function(event) {
    output("opened", "Connected to " + event.currentTarget.url);
  };

  socket.onmessage = function(event) {
    var message = event.data;
    output("received", "<<< " + message);
  };

  socket.onclose = function(event) {
    output("closed", "Disconnected: " + event.code + " " + event.reason);
    socket = undefined;
  };
};

開くボタンをクリックすると、この機能が実行されます。これは新しい WebSocket を作成し、ソケット操作のそれぞれに対してコールバック関数を定義します。いずれの場合も、これは messages​ テキスト領域にメッセージを表示します。

さらに、(引き続き window.onload​ 関数の内側で) 次のコードを追加して、送信ボタンの動作を定義します。

sendBtn.onclick = function(e) {
  if (socket == undefined) {
    output("error", 'Not connected');
    return;
  }
  var text = document.getElementById("input").value;
  socket.send(text);
  output("sent", ">>> " + text);
};

開く操作と同様に、この関数はソケットで send​ メソッドを呼び出し、送信された値を使用して output​ 関数を呼び出します。

最後に、window.onload​ 関数の終了前に次のコードを追加して、閉じるボタンの動作を定義します。

closeBtn.onclick = function(e) {
  if (socket == undefined) {
    output('error', 'Not connected');
    return;
  }
  socket.close(1000, "Close button clicked");
};

これは、閉じるボタンがクリックされたらソケットを閉じます。

アプリケーションを実行する準備ができました。

アプリのローカル実行

アプリをローカルで実行するには、まず次のコマンドを実行してアプリをコンパイルする必要があります。

$ lein uberjar

これにより、次のコマンドで起動できる実行可能 JAR ファイルが生成されます。

$ java -jar target/demo-standalone.jar host 0.0.0.0 port 5000

上記のコマンドを実行してから、ブラウザで http://localhost:5000​ を開きます。開く、送信、閉じるボタンを備えた WebSocket ページが表示されます。何かテキストを入力してテストします。これで、クラウドにデプロイする準備ができました。

Heroku へのアプリのデプロイ

次の内容でプロジェクトルートに Procfile​ を作成します。

web: java $JVM_OPTS -jar target/demo-standalone.jar host 0.0.0.0 port $PORT

Heroku にこのファイルが必要なのは、アプリケーションを起動するために実行するコマンドを指示するためです。お気付きのように、これはローカルで実行したコマンドとよく似ています。

次に、すべてのコードを Git リポジトリに追加します。

$ git init
$ git add .
$ git commit -m "first commit"

デプロイ先の Heroku アプリを作成します。

$ heroku create

次に、コードをデプロイします。

$ git push heroku master
Counting objects: 20, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (13/13), done.
Writing objects: 100% (20/20), 7.03 KiB | 0 bytes/s, done.
Total 20 (delta 0), reused 0 (delta 0)
remote: Compressing source files... done.
remote: Building source:
remote:
remote: -----> Clojure (Leiningen 2) app detected
remote: -----> Installing OpenJDK 1.8...done
remote: -----> Installing Leiningen
remote:        Downloading: leiningen-2.5.0-standalone.jar
remote:        Writing: lein script
remote: -----> Building with Leiningen
remote:        Running: lein uberjar
remote:        Retrieving org/clojure/clojure/1.6.0/clojure-1.6.0.pom from central
...
remote: -----> Discovering process types
remote:        Procfile declares types -> web
remote:
remote: -----> Compressing... done, 58.2MB
remote: -----> Launching... done, v3
remote:        https://still-hamlet-4310.herokuapp.com/ deployed to Heroku
remote:
remote: Verifying deploy... done.
To https://git.heroku.com/immutant-feature-demo.git
 * [new branch]      master -> master

以上で、Web アプリが Heroku で稼働するようになりました。アプリケーションにアクセスして動作を確認してみましょう。

$ heroku open

heroku open​ コマンドは HTTPS​ URL を開くことに注意してください。Firefox を使用している場合、WebSocket を開こうとするとブラウザでセキュリティエラーが発生します。URL を HTTP​ URL に変更するか、別のブラウザを使用する必要があります。

Immutant で WebSocket を使用する方法についての詳細は、Immutant API のドキュメント​を参照してください。ただし、Immutant のすべての機能が Heroku で使用できるわけではないことに注意してください。シングルトンサービスやセッション複製など、クラスターを必要とする機能は正しく動作しません。 代わりに、Heroku Scheduler アドオン​やキャッシュ用の Memcached アドオン​など、その他のソリューションを使用することをお勧めします。

関連カテゴリー

  • Clojure
データベース支援型の Clojure Web アプリケーションの構築 Clojure を使用したデータベース接続プール

Information & Support

  • Getting Started
  • Documentation
  • Changelog
  • Compliance Center
  • Training & Education
  • Blog
  • Podcasts
  • Support Channels
  • Status

Language Reference

  • Node.js
  • Ruby
  • Java
  • PHP
  • Python
  • Go
  • Scala
  • Clojure

Other Resources

  • Careers
  • Elements
  • Products
  • Pricing

Subscribe to our monthly newsletter

Your email address:

  • RSS
    • Dev Center Articles
    • Dev Center Changelog
    • Heroku Blog
    • Heroku News Blog
    • Heroku Engineering Blog
  • Heroku Podcasts
  • Twitter
    • Dev Center Articles
    • Dev Center Changelog
    • Heroku
    • Heroku Status
  • Facebook
  • Instagram
  • Github
  • LinkedIn
  • YouTube
Heroku is acompany

 © Salesforce.com

  • heroku.com
  • Terms of Service
  • Privacy
  • Cookies
  • Cookie Preferences