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?
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.
From my handler.clj (I'm using compojure and lib-noir)
; defroutes and route/* being from Compojure
(defroutes app-routes
(route/resources "/")
(route/not-found "Not Found"))
(def all-routes [admin-routes home-routes blog-routes app-routes])
(def app (-> (apply routes all-routes)
; etc. etc.
(def war-handler (middleware/war-handler app))
Now I don't know the particulars of how WARs are expected to behave, but lets note this war-handler from lib-noir:
(defn war-handler
"wraps the app-handler in middleware needed for WAR deployment:
- wrap-resource
- wrap-file-info
- wrap-base-url"
[app-handler]
(-> app-handler
(wrap-resource "public")
(wrap-file-info)
(wrap-base-url)))
Example application CMS: https://github.com/bitemyapp/neubite/
Compojure (routing): https://github.com/weavejester/compojure
Bag of useful utilities harvested post-Noir: https://github.com/noir-clojure/lib-noir
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With