通常,Ring中间件与服务器端的使用相关联。 在这篇文章中,我将讨论如何将环中间件的概念应用于http客户端。
一个非常典型的服务器端示例可能如下所示:
(def server
(-> server-handler
wrap-transit-params
wrap-transit-response))
脱糖:
(def server (wrap-transit-response (wrap-transit-params handler)))
server
现在是一个函数,它接受一个请求哈希映射。中间件可以在发送给处理程序之前对此数据进行操作。它还可以在处理程序返回的响应哈希映射上运行。或两者兼而有之。它甚至可以操纵处理程序的执行。
服务器
上述中间件可能以非常简单的方式显示:
(1。)它在数据到达实际处理程序(请求,传入数据)之前对数据进行操作,解析正文并将结果作为值提供给:params键。它被称为预包装。
(defn wrap-transit-params [handler]
(fn [req]
(handler (assoc req :params (from-transit-str (req :body))))))
(2。)这个操纵传出数据,服务器响应,传出数据。 - 它是一个后期包装。
(defn wrap-tranist-response [handler]
(fn [req]
(let [resp (handler req)]
(update resp :body to-transit-str))))
有了这个,服务器可以接收和响应数据作为传输。
客户端
http客户端可能需要相同的行为。
(def client
(-> client-handler
wrap-transit-params
wrap-transit-response))
事实证明,即使存在一些对称性,上述中间件也不能轻易地作为客户端中间件重用。
对于客户端,他们应该像这样实现:
(defn wrap-transit-params [handler]
(fn [req]
(handler (assoc req :body (to-transit-str (req :params))))))
(defn wrap-transit-response [handler]
(fn [req]
(let [resp (handler req)]
(update resp :body from-transit-str))))
现在它可以像这样使用:
(client {:url "http://..."
:params {:one #{1 2 3}}})
因为实际上会有更多的东西被委托,所以我认为为服务器端和客户端提供可重用的中间件是乌托邦式的。
虽然这个概念对客户来说通常是有意义的,但仍有待讨论。我在网上找不到任何客户端中间件。
服务器端中间件通常在命名空间ring.middleware...
下。我的具体问题是,提供客户端中间件的库是否应该使用此命名空间。
答案 0 :(得分:0)
除非您认为使用您的新库的代码可以编写为在客户端和服务器之间完全可移植,否则我觉得使用不同的命名空间会减少混淆。找一个有趣的名字! :)