Search code examples
clojurering

Static files with clojure and ring


I am building a test clojure/ring project to learn how it works. I created an app I call "junkapp" and it has really one handler

(defn handler [request]
  {:status 200
  :headers {"Content-type" "text/html"}
  :body "Hello World"})

And also one call to wrap-resource for static content

(def app
  (wrap-resource handler "public"))

So then in my project.clj I have a reference to lein-ring and also set :handler to my junkapp.core/app

:plugins [[lein-ring "0.8.5"]]
:ring {:handler junkapp.core/app}

when I run this with lein run, everything works as expected. A call to / returns "Hello World" and a call to /test.html returns the contents of resources/public/test.html.

But then I tried to build it into a war file with

lein ring uberwar junkapp.war

and put it under the webapps/ dir of a tomcat7 server. Now when I go to any path under junkapp (so /junkapp/, /junkapp/foo, /junkapp/test.html) it always returns "Hello World" and I can't seem to make it reference the static content at all. In googling I see people just saying to use compojure.route/resources but as I am learning I'd like it to work like this and then add in more libraries later. What's going on here?


Solution

  • I think what's happening here is that there's some code in wrap-resources here, specifically this line:

    (or ((head/wrap-head #(resource-request % root-path)) request)
      (handler request))))
    

    What happens is that when built as a war file, it doesn't understand that WEB-INF/classes/ is the root of the path it should be using to serve up the static content. So it's looking for public/test.html somewhere else (perhaps the root of the .war?) and so this "or" is false so it falls through to calling the handler directly.

    I am not sure of a fix for this as I am not totally sure the internal working of how tomcat is handling this internally... that is, I dont know where it is looking to find the base path.