对于Ring来说,一个web应用开发包含四个组件(components):

  • 处理器(Handler)
  • 请求(Request)
  • 响应(Response)
  • 中间件(Middleware)

处理器(Handlers)

处理器就是一些函数,定义我们的web应用.它们接收一个参数,一个代表着一个HTTP请求的map,然后返回一个代表着HTTP响应的map.

让我们来看一个例子:

  1. (defn what-is-my-ip [request]
  2. {:status 200
  3. :headers {"Content-Type" "text/plain"}
  4. :body (:remote-addr request)})

这个函数返回了一个map,Ring可以把它转化成一个HTTP响应.响应返回一个纯文本文件,它包含的IP地址被用来访问web应用。

处理函数之后将会被各种不同的方法转换成一个web应用,这些将会在下一节被介绍.

请求(Requests)

正如前面提到的,HTTP请求通过Clojure maps表现出来.这里有一些将会一直存在的标准keys,但是请求可以(经常会)包含自定义的keys,自定义的keys通过中间件(middleware)被添加.

这些标准的keys有:

  • :server-port服务器端口.

  • :server-name解析后的服务器名称,或者服务器IP地址.

  • :remote-addr客户端的IP地址,或者发送请求的最后代理

  • :uri请求URI(域名之后的完整路径).

  • :query-string查询字符串,如果存在的话.

  • :scheme传输协议, :http:https.

  • :request-methodHTTP请求方法, :get, :head,:options, :put, :post, 或者:delete中的一个.

  • :headers包含在一个Clojure map中的相应的头部值的字符串,需要小写表示

  • :body对于请求body的一个输入流,如果需要的话.

Ring以前的版本也有下列keys.它们现在是被弃用的.

  • :content-typeThe MIME type of the request body, if known.

  • :content-lengthThe number of bytes in the request body, if known.

  • :character-encodingThe name of the character encoding used in the request body, if known.

响应(Responses)

响应mao通过处理器(handler)被创建,包含三种keys

  • :statusHTTP状态码,例如200, 302, 404等.

  • :headers一个Clojure map里面存放着header names到header values.这些值要么是字符串,在这种情况下一个name/value header将会被发送到HTTP响应,或者是一个字符串的集合,这种情况下一个name/value header将会对每个值发送.

  • :body响应body的一种表示,如果一个响应body适合响应状态码.body可以是四种类型之一:

    • Stringbody直接被发送到客户端.

    • ISeq序列(seq)中的每一个元素被当做一个字符串发送到客户端.

    • File被引用文件的内容发送给客户端.

    • InputStream将流的内容发送到客户端.当流耗尽的时候,会被关闭.

中间件(Middleware)

中间件是高层函数为了添加额外的功能到处理器(handler).中间件的第一个参数应该是一个handler,然后它的返回值应该是一个新的处理器函数,这个函数将会调用原始的处理器.

这里有一个例子:

  1. (defn wrap-content-type [handler content-type]
  2. (fn [request]
  3. (let [response (handler request)]
  4. (assoc-in response [:headers "Content-Type"] content-type))))

这个中间件函数通过处理器,添加了一个"Content-type"头到每个响应.

包装这个中间件到一个处理器上:

  1. (def app
  2. (wrap-content-type handler "text/html"))

这里定义了一个新的处理器,app包含中间件wrap-content-type包装过的处理器handler.

线程化的宏(->)可以使中间件连接在一起:

  1. (def app
  2. (-> handler
  3. (wrap-content-type "text/html")
  4. (wrap-keyword-params)
  5. (wrap-params)))

中间件经常使用在Ring中,而且用于提供更多的功能,除了处理原始的HTTP请求之外.在Ring标准库中,参数,会话和文件上传全部是通过中间件被处理的.