访问Compojure查询字符串

11
我正在尝试从URL查询字符串中获取一个值,但返回的似乎是一个映射表。然而,当我使用下面的代码时,它没有按预期处理。请问如何访问返回的查询字符串数据结构中的特定值?

http://localhost:8080/remservice?foo=bar
(defroutes my-routes
  (GET "/" [] (layout (home-view)))
  (GET "/remservice*" {params :query-params} (str (:parameter params))))

这里有两个问题。这个函数需要一个参数吗?GET 是什么?我问这个的原因是,你应该能够从 params 中提取出你所需的信息,但是 params 在哪里呢? - octopusgrabbus
4个回答

21
你需要将你的处理程序包装在 compojure.handler/apicompojure.handler/site 中才能添加适当的中间件以访问 :query-params。这在 defroutes 中过去是自动完成的,但现在不再自动完成。一旦你这样做了,{params :query-params} 解构形式会导致当你使用 foo=bar 作为查询字符串命中 /remservice 时,params 被绑定到 {"foo" "bar"}
(或者你可以手动添加 wrap-params 等 -- 这些位于各种 ring.middleware.* 命名空间中;请参见 Compojure 1.0.1 中有关它们名称的 compojure.handler 的代码(链接到相关文件)。)
例如:
(defroutes my-routes
  (GET "/remservice*" {params :query-params}
       (str params)))

(def handler (-> my-routes compojure.handler/api))

; now pass #'handler to run-jetty (if that's what you're using)

如果您现在访问http://localhost:8080/remservice?foo=bar,则应该会看到{"foo" "bar"} -- 这是解析为Clojure映射的查询字符串的文本表示。


好的,我已经得到了一个返回地图的结果,但是我似乎无法访问单个条目,例如(:foo params)或(get params foo)或(map :foo params)都没有返回任何内容。我认为这就是我对返回的地图结构的主要困惑所在。 - Dale
2
这是因为键以字符串形式保存 - 您需要使用 (get params "foo")。或者,您可以使用 :params 而不是 :query-params - Compojure 的 api 添加了 wrap-keyword-params 中间件,因此 :params 映射被转换为关键字 - 但请注意,:params 包括两种类型的参数(另一种是表单参数; 查询参数覆盖表单参数在 :params 映射中)。 - Michał Marczyk
你如何做类似这样的事情:/users/123?sort=desc?我有参数传递到向量中。 - Justin Thomas

1
在compojure 1.2.0的默认应用程序中,默认包含查询字符串中间件。您可以像这样检查请求。
(GET "/" request (str request))

它应该包含很多内容,包括 params 键。
{ . . .  :params {:key1 "value1" :key2 "value2} . . . }

因此,您可以包含一个标准的Clojure解构形式来访问响应中的查询参数。
(GET "/" {params :params} (str params))

您的页面应该看起来像以下内容。
{"key1" "value1", "key2" "value2"}

正如Michal在评论中所指出的那样,然而,键被转换为字符串,如果您想访问它们,需要使用get函数而不是更方便的符号查找。

(GET "/" {params :params} (get params "key1"))

;;the response body should be "value1"

0

使用 compojure 1.6.1,HTTP请求解构对我来说是这样的:

  1. project.clj:dependencies 中添加 [ring/ring-defaults "0.3.2"](因为自从1.2版本以来,compojure.handler 命名空间已被弃用,推荐使用 [ring-defaults]
  2. your.routes.namespace 中的 :require 中添加 [ring.middleware.defaults :refer :all]
  3. your.routes.namespace 中添加 (def site (wrap-defaults app site-defaults)),其中 app 是通过 (defroutes app ... 声明的
  4. project.clj 中添加 :ring {:handler your.routes.namespace/site}

-1

我在compojure 1.1.5中很幸运,不需要包装器,可以使用:as指令

(GET "/tweet/:folder/:detail" [folder detail :as req]
  (twitter-controller/tweet folder detail (-> req :params :oauth_verifier))

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接