在Compojure中,默认情况下在/处提供index.html服务。

34

我有一个名为index.html的静态文件,当有人请求/时,我想要它被提供。通常情况下,Web服务器会默认这样做,但是Compojure不会。我该如何让Compojure在有人请求/时提供index.html呢?

这是我用于静态目录的代码:

; match anything in the static dir at resources/public
(route/resources "/")
8个回答

41

另一种方法是在其他路由中创建一个重定向或直接响应。如下所示:

(ns compj-test.core
  (:use [compojure.core])
  (:require [compojure.route :as route]
            [ring.util.response :as resp]))

(defroutes main-routes
  (GET "/" [] (resp/file-response "index.html" {:root "public"}))
  (GET "/a" [] (resp/resource-response "index.html" {:root "public"}))
  (route/resources "/")
  (route/not-found "Page not found"))

"/"路由返回public文件夹中存在的"index.html"文件响应。"/a"路由通过直接'内联'文件index.html来响应。

有关ring响应的更多信息:https://github.com/mmcgrana/ring/wiki/Creating-responses

编辑:删除不必要的[ring.adapter.jetty]导入。


6
你好。对我来说,(GET "/" [] (resp/resource-response "index.html" {:root "public"})) 运行得很完美。 - joshua
小心不要提供你不想要的内容类型。其他中间件,如wrap-content-type可能会破坏你的代码。我发布了一个答案来解决这个问题。 - fasfsfgs

28
(ns compj-test.core
  (:use [compojure.core])
  (:require
        [ring.util.response :as resp]))

(defroutes main-routes
  (GET "/" [] (resp/redirect "/index.html")))

你所要求的是将/重定向到/index.html。它就像(resp/redirect target)一样简单。没有必要过于复杂。


2
这是最直接和合乎逻辑的回应,谢谢! - scape

25

这将是一个非常简单的 Ring 中间件:

(defn wrap-dir-index [handler]
  (fn [req]
    (handler
     (update-in req [:uri]
                #(if (= "/" %) "/index.html" %)))))

只需使用此函数包装您的路由,请求/会在您的代码看到它们之前被转换为/index.html的请求。

(def app (-> (routes (your-dynamic-routes)
                     (resources "/"))
             (...other wrappers...)
             (wrap-dir-index)))

3
我的观点是:Compojure 不会做到这一点,因为使用 Ring 更容易实现。你的 Clojure Web 技术栈不是一个全面的平台,而是一系列可插拔和专业化的工具。用专门设计用于解决问题 X 的工具来解决它。 - amalloy

19

这个很好用,不需要编写环中间件。

(:require [clojure.java.io :as io])

(defroutes app-routes 
(GET "/" [] (io/resource "public/index.html")))

不知道是否回答了问题,但对我所需的东西有帮助!点赞!谢谢! - leontalbot
小心不要提供你不想要的内容类型。其他中间件,如wrap-content-type可能会破坏你的代码。我发布了一个答案来解决这个问题。 - fasfsfgs

13

在查看了这里很多答案之后,我正在使用以下代码:

(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"))))
  • 无需重定向;
  • 不需要其他中间件;
  • index.html 位于正确的文件夹中(resources/public/index.html);
  • 它可以与其他中间件一起使用(使用某些ring默认中间件时,许多答案会出错);
  • 它提供内容类型,因此可以与wrap-content-type中间件一起使用。

请查看ring-defaults。它有您应该在项目中使用的最佳实践中间件。


获取表单缺少空参数[],否则这正是我所需要的,谢谢! - hequ
@hequ 谢谢!已经更新了答案,加上了那些缺失的括号。 - fasfsfgs
resp/content-type 应该被包装在一个表单中吗? - Petrus Theron

3

最近我发现当Clojure/Compojure应用程序作为.war在Jetty或Tomcat下运行时,@amalloy的答案无法正常工作。在这种情况下,需要更新:path-info。此外,我认为这个版本可以处理任何路由,而不仅仅是“根”路由。

(defn- wrap-dir-index [handler]
  (fn [request]
    (handler
     (let [k (if (contains? request :path-info) :path-info :uri) v (get request k)]
       (if (re-find #"/$" v)
         (assoc request k (format "%sindex.html" v))
         request)))))

请参阅:https://groups.google.com/forum/#!msg/compojure/yzvpQVeQS3w/RNFkFJaAaYIJ 更新:用可运行的版本替换了示例。

1
当其他代码无法运行时,请尝试使用此代码。
(GET "/about/" [] (ring.util.response/content-type
                     (ring.util.response/resource-response "about/index.html" {:root "public"}) "text/html"))

2
请在您的答案中添加一些解释,以使其对其他读者更有用。 - Mohit Jain
很棒的答案。它使用ring提供的解决方案指定了其内容类型的资源。 - fasfsfgs

0
只是一个考虑,Binita,我一直遇到的问题。尽管我找不到任何关于定义Compojure路由顺序重要性的文档,但我发现这样做行不通。
(GET "/*" [] r/static) 
(GET "/" [] (clojure.java.io/resource "public/index.html"))

虽然这个可以工作

(GET "/" [] (clojure.java.io/resource "public/index.html"))
(GET "/*" [] r/static) 

显然,*也匹配空字符串,但我认为顺序根本不重要。


小心不要提供你不想要的内容类型。其他中间件,如wrap-content-type可能会破坏你的代码。我发布了一个答案来解决这个问题。 - fasfsfgs

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