3

compojure.core/GET 接受描述 URI 的字符串或描述正则表达式的向量作为路由定义参数,以匹配从 URI 中提取的参数以及 URI 本身。您可以在此处找到文档Routes in Detail

来自我的 REPL(从头开始,这个问题结尾的 leiningen 的 project.clj)

user> (use '[compojure.core :only [GET]])
nil
user> (def h (GET "/" [] "hello"))
#'user/h
user> (h {:uri "/" :request-method :get})
{:status 200, :headers {"Content-Type" "text/html; charset=utf-8"}, :body "hello"}

到目前为止一切顺利,普通的香草路线

以下是使用向量进行路由的示例:

user> (def h2 (GET ["/foo/:id" :id #"[0-9]+"] [] "hello from foo"))
#'user/h2
user> (h2 {:uri "/foo/123" :request-method :get})
{:status 200, :headers {"Content-Type" "text/html; charset=utf-8"}, :body "hello from foo"}
user> (h2 {:uri "/foo/abc" :request-method :get})
nil

一切都还好;你可以看到它只匹配数字:id的请求

现在来了我不明白的部分:

user> (def v ["/foo/:id" :id #"[0-9]+"])
#'user/v
user> (def h3 (GET v [] "hello again from foo"))
#'user/h3
user> (h3 {:uri "/foo/abc" :request-method :get})
IllegalArgumentException No implementation of method: :route-matches of protocol: #'clout.core/Route found for class: clojure.lang.PersistentVector  clojure.core/-cache-protocol-fn (core_deftype.clj:541)

任何人都可以解释为什么处理程序在使用变量而不是文字向量定义时在评估时失败的原因吗?

如果您想复制确切的环境,这是我的 leiningen 项目文件 project.clj:

(defproject cljlab "0.1.0-SNAPSHOT"
  :description "FIXME: write description"
  :url "http://example.com/FIXME"
  :license {:name "Eclipse Public License"
            :url "http://www.eclipse.org/legal/epl-v10.html"}
  :dependencies [[org.clojure/clojure "1.5.1"]
                 [org.clojure/clojure-contrib "1.2.0"]
                 [compojure "1.1.5"]])
4

1 回答 1

3

问题是 compojure 的 GET 是一个宏,而不是一个函数。宏在编译时运行,所以它看不到“v”的值是什么。查看为 h2 和 h3 生成的代码之间的区别:

user> (pprint (macroexpand-1 '(GET ["/foo/:id" :id #"[0-9]+"] [] "hello from foo")))
      (compojure.core/make-route
      :get
      (clout.core/route-compile "/foo/:id" {:id #"[0-9]+"})
      (clojure.core/fn
         [request__1858__auto__]
         (compojure.core/let-request
           [[] request__1858__auto__]
           "hello from foo")))

user> (pprint (macroexpand-1 '(GET v [] "hello again from foo")))
      (compojure.core/make-route
      :get
      (if (clojure.core/string? v) (clout.core/route-compile v) v)
      (clojure.core/fn
        [request__1858__auto__]
        (compojure.core/let-request
          [[] request__1858__auto__]
          "hello again from foo")))

在第一种情况下,宏能够将路由拆分为其组成部分并对其进行转换。在第二种情况下,宏只看到“v”符号。

于 2013-08-31T00:30:40.523 回答