You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为Ring/CLJ的file-response动态添加Content-Type响应头

解决Ring端点缺少Content-Type头的问题

你的Ring端点返回的响应缺少Content-Type头,确实会导致iOS/Safari无法正常播放媒体文件。以下两种方案可以解决这个问题:

方案一:使用Ring内置的wrap-content-type中间件

这个中间件会自动根据文件扩展名匹配并添加对应的Content-Type头,是最简便的方式。

应用到单个handler

直接把wrap-content-type包装在你的端点handler外层:

(require '[ring.middleware.content-type :refer [wrap-content-type]])

(def stream-partial-media
  {:summary "Stream partial media referenced by file-key"
   :parameters {:path {:file-key uuid?}}
   :handler (wrap-content-type
             (fn [{{{:keys [file-key]} :path} :parameters}]
               (let [file-key-res (file-keys/READ-UNEXPIRED file-key)]
                 (if (nil? file-key-res)
                   {:status 404
                    :body {:message "file-key not found"}}
                   (let [user-res (users/READ (:user-id file-key-res))]
                     (if (or (:dev env) (:prod env))
                       (log-ut/log-media-access {:file-id (str (:file-id file-key-res))
                                                 :username (:username user-res)}))
                     (file-response (utils/file-id-to-path (:file-id file-key-res))))))))})

全局应用(推荐)

如果多个端点都需要自动添加Content-Type,可在整个路由或应用外层包装中间件:

(require '[ring.adapter.jetty :as jetty])
(require '[ring.middleware.content-type :refer [wrap-content-type]])

;; 假设your-routes是你的路由定义
(def app
  (-> your-routes
      wrap-content-type))

(jetty/run-jetty app {:port 3000})

自定义MIME类型映射

如果默认的MIME映射不符合需求(比如你需要将mp3映射为audio/mp3而非标准的audio/mpeg),可以传入:mime-types参数:

(wrap-content-type handler 
                   {:mime-types {"mp3" "audio/mp3"
                                 "mp4" "video/mp4"}})

方案二:手动添加Content-Type头

如果不想依赖中间件,可以手动解析文件扩展名并添加对应头:

  1. 先定义一个扩展名到MIME类型的映射函数:
(defn get-content-type [file-path]
  (let [ext (-> file-path
                (clojure.string/split #"\.")
                last
                clojure.string/lower-case)]
    (case ext
      "mp4" "video/mp4"
      "mp3" "audio/mp3"
      ;; 可添加更多扩展名的映射
      "application/octet-stream")))
  1. 在handler中调用该函数,将Content-Type头加入响应:
(def stream-partial-media
  {:summary "Stream partial media referenced by file-key"
   :parameters {:path {:file-key uuid?}}
   :handler (fn [{{{:keys [file-key]} :path} :parameters}]
              (let [file-key-res (file-keys/READ-UNEXPIRED file-key)]
                (if (nil? file-key-res)
                  {:status 404
                   :body {:message "file-key not found"}}
                  (let [user-res (users/READ (:user-id file-key-res))
                        file-path (utils/file-id-to-path (:file-id file-key-res))
                        content-type (get-content-type file-path)]
                    (if (or (:dev env) (:prod env))
                      (log-ut/log-media-access {:file-id (str (:file-id file-key-res))
                                                :username (:username user-res)}))
                    ;; 给file-response的结果添加Content-Type头
                    (assoc (file-response file-path)
                           :headers {"Content-Type" content-type})))))))

内容的提问来源于stack exchange,提问作者reynoldsnlp

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 11:15:42