我是Clojure的新手,并且一直在使用Compojure编写基本的Web应用程序。不过,我正在用Compojure的defroutes
语法碰壁,我认为我需要理解它背后的“如何”和“为什么”。
似乎Ring样式的应用程序以HTTP请求映射开始,然后通过一系列中间件函数传递请求,直到它被转换为响应映射,然后将其发送回浏览器。对于开发人员来说,这种风格似乎太“低级”,因此需要像Compojure这样的工具。我可以看到在其他软件生态系统中需要更多的抽象,尤其是Python的WSGI。
问题在于我不了解Compojure的方法。我们采用以下defroutes
S表达式:
(defroutes main-routes
(GET "/" [] (workbench))
(POST "/save" {form-params :form-params} (str form-params))
(GET "/test" [& more] (str "<pre>" more "</pre>"))
(GET ["/:filename" :filename #".*"] [filename]
(response/file-response filename {:root "./static"}))
(ANY "*" [] "<h1>Page not found.</h1>"))
我知道理解所有这些的关键在于一些宏观巫术,但我还不完全理解宏(还)。我很长一段时间都盯着defroutes
来源了,但是没有得到它!这里发生了什么?理解“大创意”可能会帮助我回答这些具体问题:
workbench
功能)中访问Ring环境?例如,假设我想访问HTTP_ACCEPT标头或请求/中间件的其他部分?{form-params :form-params}
)?在解构时我可以使用哪些关键字?我真的很喜欢Clojure,但我很难过!
答案 0 :(得分:208)
答案 1 :(得分:7)
詹姆斯·里夫斯(作为Compojure的作者)在booleanknot.com发表了一篇精彩的文章,并且阅读了它,并且点击了#34;对我来说,所以我在这里重新翻译了一些(真的是我所做的一切)。
还有一个幻灯片here from the same author,可以回答这个问题。
Compojure基于Ring,它是http请求的抽象。
A concise syntax for generating Ring handlers.
那么,Ring handlers是什么?摘自doc:
;; Handlers are functions that define your web application.
;; They take one argument, a map representing a HTTP request,
;; and return a map representing the HTTP response.
;; Let's take a look at an example:
(defn what-is-my-ip [request]
{:status 200
:headers {"Content-Type" "text/plain"}
:body (:remote-addr request)})
非常简单,但也很低级。
可以使用ring/util
库更简洁地定义上述处理程序。
(use 'ring.util.response)
(defn handler [request]
(response "Hello World"))
现在我们想根据请求调用不同的处理程序。 我们可以这样做一些静态路由:
(defn handler [request]
(or
(if (= (:uri request) "/a") (response "Alpha"))
(if (= (:uri request) "/b") (response "Beta"))))
并像这样重构:
(defn a-route [request]
(if (= (:uri request) "/a") (response "Alpha")))
(defn b-route [request]
(if (= (:uri request) "/b") (response "Beta"))))
(defn handler [request]
(or (a-route request)
(b-route request)))
詹姆斯当时注意到的有趣的事情是,它允许嵌套路线,因为&#34;将两条或更多条路线组合在一起的结果本身就是一条路线&#34;。
(defn ab-routes [request]
(or (a-route request)
(b-route request)))
(defn cd-routes [request]
(or (c-route request)
(d-route request)))
(defn handler [request]
(or (ab-routes request)
(cd-routes request)))
到目前为止,我们开始看到一些看起来像使用宏可以考虑的代码。 Compojure提供了defroutes
宏:
(defroutes ab-routes a-route b-route)
;; is identical to
(def ab-routes (routes a-route b-route))
Compojure提供其他宏,例如GET
宏:
(GET "/a" [] "Alpha")
;; will expand to
(fn [request#]
(if (and (= (:request-method request#) ~http-method)
(= (:uri request#) ~uri))
(let [~bindings request#]
~@body)))
生成的最后一个函数看起来像我们的处理程序!
请务必查看James post,因为它会进行更详细的说明。
答案 2 :(得分:3)
我还没有开始使用clojure web stuff jet,但我会记下我收藏的内容。
答案 3 :(得分:3)
对于那些仍在努力寻找路线发生情况的人来说,可能就像我一样,你不理解解构的想法。
实际上阅读the docs for let
有助于清除整个“魔法价值来自哪里?”问题
我正在粘贴以下相关部分:
Clojure支持抽象结构 绑定,通常称为解构, 在let绑定列表中,fn参数 列表以及扩展到的任何宏 一个让或fn。基本的想法是a binding-form可以是数据结构 含有符号的文字 绑定到的各个部分 INIT-EXPR。绑定是抽象的 矢量文字可以绑定到 任何顺序的,而a map literal可以绑定到任何内容 是联想的。
Vector binding-exprs允许你绑定 命名为连续事物的一部分 (不仅仅是矢量),像矢量, 列表,seqs,字符串,数组和 任何支持nth的东西。基础的 顺序形式是一个矢量 绑定形式,将被绑定 来自的连续元素 init-expr,通过nth查找。在 另外,和任选地,&amp;其次 通过绑定形式将导致 绑定形式绑定到 序列的其余部分,即 部分尚未约束,抬头看看 nthnext。最后,也可选,:as 后跟一个符号会导致这种情况 符号被绑定到整个 INIT-EXPR:
(let [[a b c & d :as e] [1 2 3 4 5 6 7]]
[a b c d e])
->[1 2 3 (4 5 6 7) [1 2 3 4 5 6 7]]
Vector binding-exprs允许你绑定 命名为连续事物的一部分 (不仅仅是矢量),像矢量, 列表,seqs,字符串,数组和 任何支持nth的东西。基础的 顺序形式是一个矢量 绑定形式,将被绑定 来自的连续元素 init-expr,通过nth查找。在 另外,和任选地,&amp;其次 通过绑定形式将导致 绑定形式绑定到 序列的其余部分,即 部分尚未约束,抬头看看 nthnext。最后,也可选,:as 后跟一个符号会导致这种情况 符号被绑定到整个 INIT-EXPR:
(let [[a b c & d :as e] [1 2 3 4 5 6 7]]
[a b c d e])
->[1 2 3 (4 5 6 7) [1 2 3 4 5 6 7]]
答案 4 :(得分:1)
解构的问题是什么({form-params:form-params})?在解构时我可以使用哪些关键字?
可用的键是输入映射中的键。可以在let和doseq形式内部进行解构,或者在fn或defn的参数内部进行解构
以下代码有望提供信息:
(let [{a :thing-a
c :thing-c :as things} {:thing-a 0
:thing-b 1
:thing-c 2}]
[a c (keys things)])
=> [0 2 (:thing-b :thing-a :thing-c)]
一个更高级的示例,显示了嵌套解构:
user> (let [{thing-id :id
{thing-color :color :as props} :properties} {:id 1
:properties {:shape
"square"
:color
0xffffff}}]
[thing-id thing-color (keys props)])
=> [1 16777215 (:color :shape)]
明智地使用时,解构通过避免样板数据访问来淡化代码。通过使用:as和打印结果(或结果的键),您可以更好地了解您可以访问的其他数据。