使用Compojure从数据库中提供二进制文件

7

我有以下路由定义:

(require '[compojure.core :as ccore]
         '[ring.util.response :as response])

(def *main-routes*
     (ccore/defroutes avalanche-routes
       (ccore/GET "/" [] "Hello World 2")
       (ccore/GET "/images/:id" [id] (get-image-response id))))

在这个例子中,请求/像魔法一样工作,并返回预期的Hello World 2
get-images-response方法定义如下:
(defn get-image-response
  [id]
  (let [record (db/get-image id false)]
    (-> (response/response (:data record))
        (response/content-type (:content-type record))
        (response/header "Content-Length" (:size record)))))

我得到了404错误,所以二进制文件的服务还不完全工作。有什么想法为什么会这样?

编辑: 好的,问题与请求在/images/name.jpg上的图像有关。一旦我删除了.jpg,处理程序就会被调用。所以问题变成如何匹配除扩展名以外的任何内容?

2个回答

12

Compojure使用clout进行路由匹配。 在clout路由中,点字符具有特殊含义。 它表示令牌分隔符,类似于斜杠字符。 下列字符在clout中都具有这个含义:/ . , ; ?

这意味着像"/images/:id"这样的路由不会匹配形式为/images/name.jpg的URI,因为imagesnamejpg在clout中各自表示一个单独的token。

为了匹配它,您可以根据需要以多种不同方式组合路由。

如果所有图像都具有.jpg扩展名,则最简单的方法是:

(GET "/images/:id.jpg" [id] ...)

如果扩展名不同,你可以采取以下措施:

(GET "/images/:name.:extension" [name extension] ...)

如果你想限制扩展名,你可以向 compojure/clout 传递一个正则表达式:

(GET ["/images/:name.:ext", :ext #"(jpe?g|png|gif)"] [name ext] ...)

你还可以使用通配符,这样会更不精确,会匹配任何以 /images/ 开头的 URI:

(GET "/images/*" [*] ...)

感谢您提供的信息,我会给您点赞,因为它是正确的并且与我的问题相关。不幸的是,我的真正问题是在clojure-couchdb库中的一个错误,我已经修复了它。我将在另一个答案中包含所有细节,以便其他人可以参考。 - Pieter Breed

5
在这种情况下,真正的答案是clojure-couchdb库中存在一个错误。修补程序可以在这里的github上找到。
它归结为通过clj-http发送的请求中添加{:as :byte-array}映射参数和值到couch的api。
我的代码中的另一个问题是,当ring渲染字节数组时,它不知道该怎么做。我没有对ring进行修补,而是将字节数组包装到java.io.ByteArrayInputStream中。以下是处理下载的完整代码:
(defn get-image-response
  [id]
  (let [record (db/get-image id false)]
    (-> (response/response (new java.io.ByteArrayInputStream (:data record)))
        (response/content-type (:content-type (:content-type record)))
        (response/header "Content-Length" (:size record)))))

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