Ring adapter(HTTP server) with async and websocket extension
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 extension.
HTTP Kit is (almost) drop-in replacement of ring-jetty-adapter
Hello, Clojure HTTP server
run-server starts a Ring-compatible HTTP server. You may want to do routing with compojure
Options:
:ip: which IP to bind, default to 0.0.0.0
:port: which port listens for incoming requests, default to 8090
:thread: How many threads to compute response from request, default to 4
:worker-name-prefix: worker thread name prefix, default to worker-: worker-1worker-2....
:queue-size: max requests queued waiting for thread pool to compute response before rejecting, 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 request exceeds this limit, default to 8388608(8M)
:max-line: length limit for HTTP initial line and per header,
414(Request-URI Too Long) will be returned if exceeding this limit, default to 8192(8K),
relevant discussion on Stack Overflow
Stop/Restart Server
run-server returns a function that stops the server, which can take an optional timeout(ms) param to wait for existing requests to be finished.
Unified Async/Websocket API
The with-channel API is not compatible with the RC releases. The new one is better and much easier to understand and use. The old documentation is here
Unified asynchronous channel interface for HTTP (streaming or long-polling) and WebSocket.
Channel defines the following contract:
open?: Returns true iff channel is open.
close: Closes the channel. Idempotent: returns true if the channel was actually closed, or false if it was already closed.
websocket?: Returns true iff channel is a WebSocket.
send!:
Sends data to client and returns true if the data was successfully written to the output queue, or false if the
channel is closed. Normally, checking the returned value is not needed. This function returns immediately (does not
block).
Data is sent directly to the client, NO RING MIDDLEWARE IS APPLIED.
Data form: {:headers _ :status _ :body _} or just body. Note that :headers
and :status will be stripped for WebSockets and for HTTP streaming responses
after the first.
on-receive:
Sets handler (fn [message-string || byte[]) for notification of client WebSocket
messages. Message ordering is guaranteed by server.
on-close:
Sets handler (fn [status]) for notification of channel being closed by the
server or client. Handler will be invoked at most once. Useful for clean-up. Status can be `:normal`, `:going-away`, `:protocol-error`, `:unsupported`, `:unknown`, `:server-close`, `:client-close`
HTTP Streaming example
First call of send!,
sends HTTP status and Headers to client
After the first, send! sends a chunk to client
close sends an empty chunk to client, marking the end of the response
Client close notification printed via on-close
Long polling example
Long polling is very much like streaming
chat-polling is a realtime chat example of using polling
WebSocket example
Two-way communication between client and server
Can easily degrade to HTTP long polling/streaming, due to the unified API
send! with java.lang.String, a text frame assembled and sent to client
send! with java.io.InputStream or byte[], a binary frame assembled and sent to client
For WebSocket Secure connection, one option is stud (self-signed certificate may not work with websocket).
Nginx can do it, too.
Control WebSocket handshake
The with-channel does the WebSocket handshake automatically. In case if you want to control it, e.g., to support WebSocket subprotocol,
here is a workaround. cgmartin's gist is a good place to get inspired.
Routing with Compojure
Compojure can be used to do the routing, based on uri and method
Recommended server deployment
http-kit runs alone happily, handy for development and quick deployment.
Use of a reverse proxy like Nginx,
Lighthttpd, etc in serious production is encouraged.
They can also be used to add https support.
They are fast and heavily optimized for static content.
They can be configured to compress the content sent to browsers