Compojure路由中更新后的Atom值未生效问题排查与解决求助
问题分析与解决方案
你的核心问题在于Compojure路由定义时的提前求值:当你写(route/not-found {:status 400 :body @my-atom})时,@my-atom会在app被定义的瞬间就被解析成当时的Atom值(也就是"foobar"),之后无论你怎么更新Atom,这个静态的响应map都不会再变化了。
要让路由响应Atom的动态更新,你需要让响应逻辑延迟到每次请求时才执行——也就是把响应变成一个函数,而不是静态的map。
修正后的基础写法
直接把not-found的响应改成一个接收请求参数的函数,每次请求过来时才去解引用Atom:
(ns mveroute (:require [org.httpkit.server :as srv] [compojure.core :as cmpj] [compojure.route :as route] [clj-http.client :as client]) (:gen-class)) (def my-atom (atom "foobar")) ;; 把not-found的响应改成函数,每次请求时才获取Atom最新值 (def app (cmpj/routes (route/not-found (fn [_req] {:status 400 :body @my-atom})))) (defn -main [& args] (reset! my-atom "hello world") (srv/run-server #'app {:port 8005}) (println @my-atom) ; 输出"hello world" ;; 现在会输出"hello world"了 (-> "http://localhost:8005" (client/get {:throw-exceptions? false}) :body println))
这样修改后,每次收到404请求时,都会调用这个匿名函数,此时才会读取Atom的当前值,自然就能拿到更新后的内容。
关于你尝试的wrap-routes问题
你之前的写法里,(route/not-found (atom-body))是直接调用了atom-body函数,相当于提前把它的返回值(初始Atom值对应的map)绑定到路由里了。正确的做法是直接传递函数本身,不要加括号调用:
(defn atom-body [_req] {:status 200 :body @my-atom}) (cmpj/defroutes wrap-found (route/not-found atom-body)) ; 这里直接传函数,不要调用 (def app (cmpj/wrap-routes #'wrap-found {}))
这样路由收到请求时,才会执行atom-body函数,获取最新的Atom值。
针对你的最终目标(CLI设置资源根目录)
如果要实现动态设置静态文件根目录的功能,你可以把根目录存在Atom里,然后写一个动态读取该目录的handler:
(def root-dir (atom "./default-public")) ; 默认根目录 (defn static-file-handler [req] (let [file-path (str @root-dir (:uri req)) file (clojure.java.io/file file-path)] (cond (.exists file) {:status 200 :body (slurp file)} :else {:status 404 :body (str "File not found in root: " @root-dir)}))) (def app (cmpj/routes (cmpj/GET "/*" [] static-file-handler) ; 处理所有静态文件请求 (route/not-found (fn [_] {:status 404 :body (str "404 - Root dir: " @root-dir)})))) ;; 在CLI启动时可以通过参数更新根目录 (defn -main [& args] (when-let [new-root (first args)] (reset! root-dir new-root)) (srv/run-server #'app {:port 8005}) (println "Serving files from:" @root-dir))
这样启动时传参数clj -m mveroute ./my-custom-public,就能动态切换静态文件根目录,后续请求都会使用新目录。
内容的提问来源于stack exchange,提问作者Will
相关产品推荐
相关产品推荐

