Archives for

Compojure/Ringのmiddlewareについて

ClojureでWebアプリを作っていて、よくわからないもやもやした概念の一つはmiddlewareでしょう。

概念なので、どういうものかがわかってしまえば、関数のスタイルということがわかり、悩むこともなくなります。

middlewareは、handlerを受け取り、引数が一つの関数を返します。

その返す関数というのが、リクエストを受け取り、handlerを返す関数です。

つまり、もっともシンプルなmiddlewareというのはこんなものです。

(defn hoge-middleware [handler]
  (fn [request]
    (println request)
    (handler request)))

handlerにrequestを適用させると、handlerが返ります。

ちなみに、requestというのは、ringの仕様に沿ったハッシュマップです。

ということで、middlewareは、こんな感じで、handlerを延々と渡していくことで利用が可能というわけです。

(def app
  (-> (routes (routes-a routes-b)
      middleware-a
      middleware-b
      middleware-c))

とてもシンプルな考え方で素晴らしいと思いました。

Read More

ClojureのImmutantでWebサーバ起動時に外部からのアクセスを制限/解放するには?

ClojureのWebアプリケーションフレームワークLuminusでは、2.0からImmutantというサーバ関連のライブラリが使われています。

Immutantは、Webサーバの他に、スケジューラやメッセージングといったライブラリも含んだJBOSS関係のClojure向けライブラリです。

僕はWebサーバ、そしてバッチ処理用に使っています。

で、これが、アプリケーションをちょろっと書いてサーバ起動して、ローカルで見るとちゃんとHTMLが表示されるんですが、ローカルLAN内の他のPCからだと見ることができません。

不思議ですね。(よくあるWebアプリケーションフレームワークって、すぐにポート指定したら見れたりするでしょ)

原因はここを見ると書いてあります。

immutant.web

options can be a map or kwargs, with these valid keys [default]:

:host The interface bind address [“localhost”]
:port The port listening for requests [8080]
:path Maps the handler to a prefix of the url path [“/”]
:virtual-host Virtual host name[s] (a String or a List of Strings) [nil]
:dispatch? Invoke handlers in worker thread pool [true]
Note the web server only binds to the loopback interface, by default. To expose your handler to the network, set :host to an external IP address, or use “0.0.0.0” to bind it to all interfaces.

つまり、 Luminus上で、4000番ポート、他のPCからも接続可能な状態でホストを指定して起動するには、

(defn -main
  [& args]
  (.addShutdownHook (Runtime/getRuntime) (Thread. stop-server))
  (start-server (concat ["port" 4000 "host" "0.0.0.0"] args))
  (timbre/info "server started on port:" (:port @server)))

と指定すればいいことがわかりました。

ここ、最初ちょっとした詰まりポイントかもです。

Read More

ClojureのCompojure(のmiddleware)でリダイレクトするときは:urlだけでなく:path-infoも変えないといけない件

誰得なのかわからないニッチネタを投下します

Clojure製のフレームワーク、CompojureでリクエストされたURLを元にリクエストマップを変更して再びリダイレクトをかけるには:urlだけでなく:path-infoも変えないと動きません。

これに気付いたのは、Clojureのトレイリングスラッシュリダイレクトのためのコードを探していた時でした。

ここに、スラッシュなしの場合にスラッシュありへリダイレクトするコードがありますが、動いていません(というような質問だった)。 :url部分以外でも間違っていた箇所はありましたが、それらはケアレスミスかと思われます。

で、他にもこの手のコードを検索することができますが、:urlを変更しているのみなので、少なくともいまのcompojureでは動きません。

ということで、下記のように変更することで動くことが確認できました。

※これはmiddlewareとして、handlerに対して使ってください。

;;; http://stackoverflow.com/questions/14507445/ring-solution-to-redirect-missing-trailing-slash-urls
;
(defn good-response? [resp]
  (and resp (not= (:status resp) 404)))
;
(defn wrap-slash [handler]
  (fn [{:keys [uri] :as req}]
    (let [resp (handler req)]
      (if (or (good-response? resp) (.endsWith uri "/"))
        resp
        (let [added-slash (str uri "/")]<br />
          (if (good-response? (handler (-> req
                                           (assoc :uri added-slash)
                                           (assoc :path-info added-slash))))
            (redirect added-slash)
            resp))))))

gistにも貼っています。

トレイリングスラッシュ関連でお困りの方どうぞ(いるのか)

compojureのコードなどを読んだり、各種middlewareの挙動を確かめたりしたので、そこそこに勉強になりました。

Read More