如何将 GridFS 文件流式传输到 Clojure/Monger 中的 Web 客户端?
How can I stream GridFS files to web clients in Clojure/Monger?
我有一个使用 Clojure、Clojurescript 和 Monger 的网络应用程序。文档通过 GridFS 上传并存储在 Mongo 中。可以请求下载相同的文件;目前这是通过将文件写入(服务器的)磁盘并将其作为静态文件提供来完成的,但这有点尴尬;如何直接在 Clojure/Java 中提供由 GridFS 对象表示的文件?路由由 Ring/Compojure 处理。
事实证明,Luminus 中使用的 Ring/Compojure 基础设施能够 return 输出流,无需接触驱动器即可轻松传输文件。
(ns my-app.routes.updown
"File uploading and insertion into database"
(:use compojure.core)
(:require [my-app.db.core :as db] ;; all the db functions you see here are just wrappers for the Monger functions you'd expect
[ring.util.response :as r]
[ring.util.io :as io]))
(defn make-file-stream
"Takes an input stream--such as a MongoDBObject stream--and streams it"
[file]
(io/piped-input-stream
(fn [output-stream]
(.writeTo file output-stream))))
(defn download-file-by-id "Downloads the requested file, if privileges are allowed"
[id-string]
(let [mongo-file (db/find-file-by-id id-string)
file-map (db/map-from-mongo-obj mongo-file)
content-type (-> file-map :metadata :contentType)
file-name (-> file-map :filename)]
(-> mongo-file
make-file-stream
r/response
(#(r/header % "Content-Disposition" ; to get the right default file-name
(str "attachment; filename=\"" file-name "\"")))
(#(r/header % "Content-Type" content-type))))) ; final wrapper: offer the right "open with" dialogue
;; this is called by my main routes def like so:
;; (notice no extra wrappers needed, as wrapping took place in download-file-by-id)
;; (defroutes home-routes
;; (GET "/files/:id-string" [id-string]
;; (up/download-file-by-id id-string)))
我有一个使用 Clojure、Clojurescript 和 Monger 的网络应用程序。文档通过 GridFS 上传并存储在 Mongo 中。可以请求下载相同的文件;目前这是通过将文件写入(服务器的)磁盘并将其作为静态文件提供来完成的,但这有点尴尬;如何直接在 Clojure/Java 中提供由 GridFS 对象表示的文件?路由由 Ring/Compojure 处理。
事实证明,Luminus 中使用的 Ring/Compojure 基础设施能够 return 输出流,无需接触驱动器即可轻松传输文件。
(ns my-app.routes.updown
"File uploading and insertion into database"
(:use compojure.core)
(:require [my-app.db.core :as db] ;; all the db functions you see here are just wrappers for the Monger functions you'd expect
[ring.util.response :as r]
[ring.util.io :as io]))
(defn make-file-stream
"Takes an input stream--such as a MongoDBObject stream--and streams it"
[file]
(io/piped-input-stream
(fn [output-stream]
(.writeTo file output-stream))))
(defn download-file-by-id "Downloads the requested file, if privileges are allowed"
[id-string]
(let [mongo-file (db/find-file-by-id id-string)
file-map (db/map-from-mongo-obj mongo-file)
content-type (-> file-map :metadata :contentType)
file-name (-> file-map :filename)]
(-> mongo-file
make-file-stream
r/response
(#(r/header % "Content-Disposition" ; to get the right default file-name
(str "attachment; filename=\"" file-name "\"")))
(#(r/header % "Content-Type" content-type))))) ; final wrapper: offer the right "open with" dialogue
;; this is called by my main routes def like so:
;; (notice no extra wrappers needed, as wrapping took place in download-file-by-id)
;; (defroutes home-routes
;; (GET "/files/:id-string" [id-string]
;; (up/download-file-by-id id-string)))