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

时间:2010-10-21 14:23:35

标签: clojure binary-data compojure

我有以下路线定义:

(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 个答案:

答案 0 :(得分:11)

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

这意味着"/images/:id"之类的路由与/images/name.jpg形式的uri不匹配,因为imagesnamejpg各自代表一个单独的令牌在影响力。

为了与之匹配,您可以根据需要以多种不同的方式撰写路线。

如果您的所有图片都有.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/*" [*] ...)

答案 1 :(得分:4)

在这种情况下,真正的答案是clojure-couchdb库中存在一个错误。该补丁可用on github here

归结为将{:as:byte-array}映射参数和值添加到通过clj-http发送到couch的api的请求。

我的代码中的另一个问题是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)))))