(:use org.httpkit.server)
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)
run-server
starts a Ring-compatible HTTP server, routing using compojure
(defn app [req]
{:status 200
:headers {"Content-Type" "text/html"}
:body "hello HTTP!"})
(run-server app {:port 8080})
:ip
: which IP to bind, default to 0.0.0.0
:port
: which port listens incomming request, default to 8090:thread
: How many threads to compute response from request, default to 4:worker-name-prefix
: woker thread name prefix, default to worker-
: worker-1
worker-2
....:queue-size
: max requests queued waiting for threadpool to compute response before reject, 503(Service Unavailable) is returned to client if queue is full, default to 20K:max-body
: length limit for request body in bytes, 413(Request Entity Too Large) is returned if exceeds this limit, default to 8388608(8M):max-line
: length limit for HTTP inital line and per header,
414(Request-URI Too Long) will be returned if exceeds this limit, default to 4096(4K),
relevant discusstion on stackoverflowif-ws-request
or when-ws-request
: get the websocket connection, returns websocket handshake
on-mesg
: register a fn to be called when there is string message from clientsend-mesg
: send string message to client. Clojure data can be converted to string using
JSON or ednclose-conn
: close the websocket connectionon-close
: register a fn to be called when the connecton is closedFor 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
(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})
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
(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})
Compojure Can be used to do the routing, based on uri and method
(: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 "<p>Page not found.</p>")) ;; all other, return 404
(run-server (site #'all-routes) {:port 8080})
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:
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;
}
}