为什么Ring的资源响应会以application/octet-stream内容类型响应?

10

我正在尝试弄清楚为什么Ring的resource-response选择使用application/octet-stream内容类型进行响应。最近,我更新了一些示例代码,那是我学习的样本代码,使其使用较新的ring-defaults。在使用ring-defaults之前,此代码以html内容类型响应。为什么现在会选择octet-stream?

(ns replays.handler
  (:require [compojure.core :refer [GET defroutes]]
            [compojure.route :as route]
            [ring.util.response :refer [response resource-response]]
            [ring.middleware.json :as middleware]
            [ring.middleware.defaults :refer [wrap-defaults api-defaults]]))

(defroutes app-routes
  (GET  "/" [] (resource-response "index.html" {:root "public"}))
  (GET  "/widgets" [] (response [{:name "Widget 1"} {:name "Widget 2"}]))
  (route/resources "/public")
  (route/not-found "not found"))

(def app
  (-> app-routes
      (middleware/wrap-json-body)
      (middleware/wrap-json-response)
      (wrap-defaults api-defaults)))

关于版本号,这里是项目文件...

(defproject replays "0.1.0-SNAPSHOT"

  :url "http://example.com/FIXME"
  :description "FIXME: write description"

  :plugins [[lein-pdo "0.1.1"]
            [lein-ring "0.9.3"]
            [lein-cljsbuild "1.0.5"]]

  :dependencies [[org.clojure/clojure "1.6.0"]
                 [org.clojure/core.async "0.1.346.0-17112a-alpha"]
                 [org.clojure/clojurescript "0.0-3126"]
                 [org.omcljs/om "0.8.8"]
                 [ring/ring-core "1.3.2"]
                 [ring/ring-json "0.3.1"]
                 [ring/ring-defaults "0.1.4"]
                 [compojure "1.3.2"]
                 [cljs-http "0.1.29"]]

  :source-paths ["src/clj"]

  :ring {:handler replays.handler/app}

  :cljsbuild {:builds [{:id "dev"
                        :source-paths ["src/cljs"]
                        :compiler {:output-to "resources/public/js/app.js"
                                   :output-dir "resources/public/js/out"
                                   :optimizations :none
                                   :source-map true}}]}

  :aliases {"up" ["pdo" "cljsbuild" "auto" "dev," "ring" "server-headless"]}

  :profiles {:dev {:dependencies [[javax.servlet/servlet-api "2.5"]
                                  [ring-mock "0.1.5"]]}})

3
我不确定,但我认为这与 wrap-content-type 使用 URI 上的扩展名来设置内容类型标头有关?可以通过在URI中添加扩展名或手动设置内容类型 (assoc-in (resource-response ...) [:headers "Content-Type"] "text/html") 来解决这个问题。 - noisesmith
1
我相信您的建议是做这件事的适当方式。同时也提供了一个类似的函数:http://ring-clojure.github.io/ring/ring.util.response.html#var-content-type - Ryan
是的,我避免回答,因为虽然我建议的方法可以工作,但它也感觉像是手动完成中间件应该为您完成的工作。但是,如果您查看该函数的源代码,它调用header,而header几乎完全执行了我上面提到的操作。 - noisesmith
这不是答案,而更像是一个解决方法 - 我不确定原因。 - noisesmith
我曾经遇到过同样的问题,通过尝试一个带有 .htm 扩展名的 URL,确认了这会返回 text/html 的内容类型。同样的,.rss 会返回 application/rss+xml - Kris
1个回答

10

出现这种情况是因为 api-defaults (实际上是 ring.middleware.content-type)尝试根据您传递给它的数据猜测您的内容类型。它使用文件扩展名来做到这一点,而您使用的是 resource-response,所以没有扩展名。因此,默认情况下 ring.middleware.content-type 使用 application/octet-stream

解决方案是像下面这样向响应提供您的内容类型:

(ns app.routes
  (:require [compojure.core :refer [defroutes GET]]
            [ring.util.response :as resp]))

(defroutes appRoutes
  ;; ...
  ;; your routes
  ;; ...
  (GET "/"
       resp/content-type (resp/resource-response "index.html" {:root "public"}) "text/html"))

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