--- layout: doc title: HTTP server ---

Ring adapter(HTTP server) with async and websocket extenstion

{% highlight clojure %} (:use org.httpkit.server) {% endhighlight %}

The server uses an event-driven, non-blocking I/O model that makes it lightweight and scalable. It's written to conform to the standard Clojure web server Ring spec, with asynchronous and websocket extenstion. HTTP Kit is (almost) drop-in replacement of ring-jetty-adapter

A new unified Async/Websocket API(working in progress)

Hello, Clojure HTTP server

run-server starts a Ring-compatible HTTP server, routing using compojure

{% highlight clojure %} (defn app [req] {:status 200 :headers {"Content-Type" "text/html"} :body "hello HTTP!"}) (run-server app {:port 8080}) {% endhighlight %}

Options:

Websocket extenstion

For WebSocket Secure connection, one option is stud (self-signed certificate may not work with websocket)

A realtime chart example: https://github.com/http-kit/chat-websocket

{% highlight clojure %} (defn chat-handler [req] (when-ws-request req ws-con ; ws-con bind to the websocket connection (on-mesg ws-con (fn [msg] (send-mesg ws-con msg) ;; echo back (close-conn ws-con))) ;; close the connection (on-close ws-con (fn [status] (println ws-con "closed"))))) (run-server chat-handler {:port 8080}) {% endhighlight %}

Asynchronous (long polling) extenstion

respond accept a standard ring-response (:status :headers :body) or just the :body

All request-level middlewares applied to req before passing to aync-handler (like any other handler)

The response is sent to client without response-level middlewares applied (a limitation, suggestions welcome)

Optional timeout facilities: timer

A realtime chart example: https://github.com/http-kit/chat-polling

{% highlight clojure %} (defn async-handler [req] ; respond is a one-time function, can be called on any thread to send the response to client (async-response respond ; just :body, can also be {:status _ :headers _ :body _} (future (respond "hello world async")))) (run-server async-handler {:port 8080}) {% endhighlight %}

Routing with Compojure

Compojure Can be used to do the routing, based on uri and method

{% highlight clojure %} (:use [compojure.route :only [files not-found]] [compojure.handler :only [site]] ; form, query params decode; cookie; session, etc [compojure.core :only [defroutes GET POST DELETE ANY context]] org.httpkit.server) (defn show-landing-page [req] ;; ordinary clojure function, accept request map ;; return landing page's html string. possible template library: ;; mustache (https://github.com/shenfeng/mustache.clj, https://github.com/fhd/clostache...) ;; enlive (https://github.com/cgrand/enlive), hiccup(https://github.com/weavejester/hiccup) ) (defn update-userinfo [req] ;; ordinary clojure function (let [user-id (-> req :params :id) ; param from uri password (-> req :params :password)] ; form param .... )) (defroutes all-routes (GET "/" [] show-landing-page) (GET "/ws" [] chat-handler) ;; websocket (GET "/async" [] async-handler) ;; asynchronous(long polling) (context "/user/:id" [] (GET / [] get-user-by-id) (POST / [] update-userinfo)) (route/files "/static/") ;; static file url prefix /static, in `public` folder (route/not-found "

Page not found.

")) ;; all other, return 404 (run-server (site #'all-routes) {:port 8080}) {% endhighlight %}

Recommended server deployment

http-kit runs alone happly, handy for development and quick deployment. Use reverse proxy like Nginx, Lighthttpd, etc in serious production is encouraged. They also add https support.

Sample Nginx configration:

{% highlight sh %} upstream http_backend { server 127.0.0.1:8090; # http-kit listen on 8090 # keepalive(resue TCP connection) improves performance keepalive 32; # both http-kit and nginx are good at concurrency } server { location /static/ { # static content alias /var/www/xxxx/public/; } location / { proxy_pass http://http_backend; # tell http-kit to keep the connection proxy_http_version 1.1; proxy_set_header Connection ""; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; access_log /var/log/nginx/xxxx.access.log; } } {% endhighlight %}