简体   繁体   中英

Serving static content from a purely Clojure web application on WildFly (Non-Immutant) - What is this VFS error?

I was asked to try and deploy a Clojure web application normally deployed on Tomcat this time on WildFly, along with a different web application done in CLJ+CLJS (which has a different issue of responding with 403 errors but that's for another time). Deployment wasn't actually an issue, but what happened afterwards was... perplexing, to say the least. While the pure Clojure web application originally on Tomcat did successfully deploy on Wildfly, none of the static content was actually accessible.

Checking the undertow server logs gave me repeated errors, here's a stack trace from one of the errors:

2016-01-26 16:57:49,069 ERROR [io.undertow.request] (default task-2) UT005023: Exception handling request to /admin-rrs-sm/js/asset-scripts.js: java.lang.IllegalArgumentException: No method in multimethod 'resource-data' for dispatch value: :vfs
at clojure.lang.MultiFn.getFn(MultiFn.java:156)
at clojure.lang.MultiFn.invoke(MultiFn.java:229)
at ring.util.response$url_response.invoke(response.clj:269)
at ring.util.response$resource_response.doInvoke(response.clj:287)
at clojure.lang.RestFn.invoke(RestFn.java:410)
at compojure.route$resources$fn__4743.invoke(route.clj:37)
at compojure.core$make_route$fn__4621.invoke(core.clj:130)
at compojure.core$wrap_route_middleware$fn__4617.invoke(core.clj:118)
at compojure.core$if_route$fn__4589.invoke(core.clj:41)
at compojure.core$if_method$fn__4581.invoke(core.clj:27)
at compojure.core$routing$fn__4628.invoke(core.clj:144)
at clojure.core$some.invoke(core.clj:2570)
at compojure.core$routing.doInvoke(core.clj:144)
at clojure.lang.RestFn.applyTo(RestFn.java:139)
at clojure.core$apply.invoke(core.clj:632)
at compojure.core$routes$fn__4632.invoke(core.clj:149)
at cemerick.friend$handler_request.invoke(friend.clj:222)
at cemerick.friend$authenticate_STAR_.invoke(friend.clj:249)
at cemerick.friend$authenticate$fn__2970.invoke(friend.clj:260)
at ring.middleware.flash$wrap_flash$fn__8494.invoke(flash.clj:35)
at ring.middleware.session$wrap_session$fn__6540.invoke(session.clj:102)
at ring.middleware.keyword_params$wrap_keyword_params$fn__8307.invoke(keyword_params.clj:35)
at ring.middleware.nested_params$wrap_nested_params$fn__8357.invoke(nested_params.clj:84)
at ring.middleware.multipart_params$wrap_multipart_params$fn__8400.invoke(multipart_params.clj:117)
at ring.middleware.params$wrap_params$fn__8273.invoke(params.clj:64)
at ring.middleware.cookies$wrap_cookies$fn__6419.invoke(cookies.clj:161)
at ring.middleware.absolute_redirects$wrap_absolute_redirects$fn__8606.invoke(absolute_redirects.clj:36)
at ring.middleware.content_type$wrap_content_type$fn__8563.invoke(content_type.clj:30)
at ring.middleware.default_charset$wrap_default_charset$fn__8583.invoke(default_charset.clj:26)
at ring.middleware.not_modified$wrap_not_modified$fn__8544.invoke(not_modified.clj:52)
at ring.middleware.x_headers$wrap_xss_protection$fn__8472.invoke(x_headers.clj:71)
at ring.middleware.x_headers$wrap_frame_options$fn__8460.invoke(x_headers.clj:38)
at ring.middleware.x_headers$wrap_content_type_options$fn__8466.invoke(x_headers.clj:53)
at ring.middleware.session$wrap_session$fn__6540.invoke(session.clj:102)
at hiccup.middleware$wrap_base_url$fn__6037.invoke(middleware.clj:12)
at ring.middleware.keyword_params$wrap_keyword_params$fn__8307.invoke(keyword_params.clj:35)
at ring.middleware.nested_params$wrap_nested_params$fn__8357.invoke(nested_params.clj:84)
at ring.middleware.params$wrap_params$fn__8273.invoke(params.clj:64)
at ring.middleware.multipart_params$wrap_multipart_params$fn__8400.invoke(multipart_params.clj:117)
at compojure.core$routing$fn__4628.invoke(core.clj:144)
at clojure.core$some.invoke(core.clj:2570)
at compojure.core$routing.doInvoke(core.clj:144)
at clojure.lang.RestFn.applyTo(RestFn.java:139)
at clojure.core$apply.invoke(core.clj:632)
at compojure.core$routes$fn__4632.invoke(core.clj:149)
at clojure.lang.Var.invoke(Var.java:379)
at reporter.listener$_contextInitialized$fn__11.invoke(listener.clj:1)
at ring.util.servlet$make_service_method$fn__9032.invoke(servlet.clj:129)
at reporter.servlet$_service.invoke(servlet.clj:1)
at reporter.servlet.service(Unknown Source)
at io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:86)
at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62)
at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36)
at org.wildfly.extension.undertow.security.SecurityContextAssociationHandler.handleRequest(SecurityContextAssociationHandler.java:78)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:131)
at io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46)
at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:64)
at io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:58)
at io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:72)
at io.undertow.security.handlers.NotificationReceiverHandler.handleRequest(NotificationReceiverHandler.java:50)
at io.undertow.security.handlers.SecurityInitialHandler.handleRequest(SecurityInitialHandler.java:76)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at org.wildfly.extension.undertow.security.jacc.JACCContextIdHandler.handleRequest(JACCContextIdHandler.java:61)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:282)
at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:261)
at io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:80)
at io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:172)
at io.undertow.server.Connectors.executeRootHandler(Connectors.java:199)
at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:774)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)

While you could actually navigate the page, none of the CSS or the JS was actually being loaded, which broke a good chunk of the application's functionality. I have already tried a number of things to try and fix this. For example, I have added some extra things to standalone.xml in order to try and point the static resources to a different location, like this:

                <host name="default-host" alias="localhost">
                <location name="/" handler="welcome-content"/>
                <location name="/images" handler="images"/>
                <location name="/js" handler="scripts"/>
                <location name="/css" handler="css"/>
                <filter-ref name="server-header"/>
                <filter-ref name="x-powered-by-header"/>
            </host>
        </server>

        <handlers>
            <file name="welcome-content" path="${jboss.home.dir}/welcome-content"/>
            <file name="images" path="${jboss.home.dir}/images"/>
            <file name="scripts" path="${jboss.home.dir}/js"/>
            <file name="css" path="${jboss.home.dir}/css"/>
        </handlers>

But, to no avail.

What is the meaning behind ":VFS"? Is there some virtual file system problem I'm not aware of?

The Clojurians Slack community, specifically #immutant, has helped me on this. It turns out that using wrap-resource starting from Ring version 1.3.2 in Wildfly causes the application to serve an empty file instead. The issue was recorded in IMMUTANT-525 where @tcrawley, the kind fellow responsible for committing a fix to this issue pointed me to include it in my own application which is found here .

(when (try-resolve 'ring.util.response/resource-data)
  (eval
    '(defmethod ring.util.response/resource-data :vfs
       [url]
       (let [conn (.openConnection url)
             vfile (.getContent conn)]
         (when-not (.isDirectory vfile)
           {:content (.getInputStream conn)
            :content-length (.getContentLength conn)
            :last-modified (-> vfile
                             .getPhysicalFile
                             ring.util.io/last-modified-date)})))))

Since my application of course doesn't have immutant 's try-resolve , you need to include the try-resolve somewhere in your application as well. You will need to include this too.

(defn require-resolve
  "Requires and resolves the given namespace-qualified symbol."
  [sym]
  (require (symbol (namespace sym)))
  (resolve sym))

(defn try-resolve
  "Tries to require and resolve the given namespace-qualified symbol, returning nil if not found."
  [sym]
  (try
    (require-resolve sym)
    (catch java.io.FileNotFoundException _)
    (catch RuntimeException _)))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM