对于Ring来说,一个web应用开发包含四个组件(components):
- 处理器(Handler)
- 请求(Request)
- 响应(Response)
- 中间件(Middleware)
处理器(Handlers)
处理器就是一些函数,定义我们的web应用.它们接收一个参数,一个代表着一个HTTP请求的map,然后返回一个代表着HTTP响应的map.
让我们来看一个例子:
- (defn what-is-my-ip [request]
- {:status 200
- :headers {"Content-Type" "text/plain"}
- :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-method
HTTP请求方法,:get
,:head
,:options
,:put
,:post
, 或者:delete
中的一个.:headers
包含在一个Clojure map中的相应的头部值的字符串,需要小写表示:body
对于请求body的一个输入流,如果需要的话.
Ring以前的版本也有下列keys.它们现在是被弃用的.
:content-type
The MIME type of the request body, if known.:content-length
The number of bytes in the request body, if known.:character-encoding
The name of the character encoding used in the request body, if known.
响应(Responses)
响应mao通过处理器(handler)被创建,包含三种keys
:status
HTTP状态码,例如200, 302, 404等.:headers
一个Clojure map里面存放着header names到header values.这些值要么是字符串,在这种情况下一个name/value header将会被发送到HTTP响应,或者是一个字符串的集合,这种情况下一个name/value header将会对每个值发送.:body
响应body的一种表示,如果一个响应body适合响应状态码.body可以是四种类型之一:String
body直接被发送到客户端.ISeq
序列(seq)中的每一个元素被当做一个字符串发送到客户端.File
被引用文件的内容发送给客户端.InputStream
将流的内容发送到客户端.当流耗尽的时候,会被关闭.
中间件(Middleware)
中间件是高层函数为了添加额外的功能到处理器(handler).中间件的第一个参数应该是一个handler,然后它的返回值应该是一个新的处理器函数,这个函数将会调用原始的处理器.
这里有一个例子:
- (defn wrap-content-type [handler content-type]
- (fn [request]
- (let [response (handler request)]
- (assoc-in response [:headers "Content-Type"] content-type))))
这个中间件函数通过处理器,添加了一个"Content-type"头到每个响应.
包装这个中间件到一个处理器上:
- (def app
- (wrap-content-type handler "text/html"))
这里定义了一个新的处理器,app
包含中间件wrap-content-type
包装过的处理器handler
.
线程化的宏(->
)可以使中间件连接在一起:
- (def app
- (-> handler
- (wrap-content-type "text/html")
- (wrap-keyword-params)
- (wrap-params)))
中间件经常使用在Ring中,而且用于提供更多的功能,除了处理原始的HTTP请求之外.在Ring标准库中,参数,会话和文件上传全部是通过中间件被处理的.