【问题标题】:Clojure Noir routing priorityClojure Noir 路由优先级
【发布时间】:2012-10-02 16:08:16
【问题描述】:

我正在使用 Noir 开发一个 Web 应用程序。但是,我遇到了路由问题。这是来自我的控制器的代码示例:

(defpage [:get "/users/add"] []
    (common/layout
      [:div.row
       [:div.span12
        [:div.page-header
         [:h2 "Add User"]]
        (form-to {:class "form-horizontal"} [:post "/users/add"]
         (user-form {:id ""
                    :first_name ""
                    :last_name ""
                    :login ""
                    :email ""
                    :admin false
                    :staff false
                    :manager false
                    :customer false})
         [:div.control-group
          [:div.controls
           (submit-button {:class "btn btn-primary"} "Edit")]])]]))


(defpage [:get "/users/:id" :id #"\d+"] {:keys [id]}
(let [user (user/get-by-id id)]
    (common/layout
      [:div.row
       [:div.span12
        [:div.page-header
         [:h2 "View User"]]
        [:h3 (str (user :first_name) " " (user :last_name))]
        [:dl.dl-horizontal
         [:dt "login"]
         [:dd (user :login)]
         [:dt "e-mail"]
         [:dd (user :email)]
         [:dt "admin"]
         [:dd (if (user :admin) [:i.icon-ok ""] [:i.icon-remove ""])]
         [:dt "staff"]
         [:dd (if (user :staff) [:i.icon-ok ""] [:i.icon-remove ""])]
         [:dt "manager"]
         [:dd (if (user :manager) [:i.icon-ok ""] [:i.icon-remove ""])]
         [:dt "customer"]
         [:dd (if (user :customer) [:i.icon-ok ""] [:i.icon-remove ""])]]
        [:div.form-actions
         [:a.btn.btn-primary {:href (str "/users/" (user :id) "/edit")} "Edit"] " "
         [:a.btn.btn-danger {:href (str "/users/" (user :id) "/remove")} "Remove"] " "
         [:a.btn {:href "/users"} "All users"]]]])))

每次我请求“/users/add”时,请求都会被路由到“/user/:id”(删除/user/add 操作时很好)。我对另一个控制器有非常相似的代码,它工作正常。可能是什么问题?如何设置路由优先级?

谢谢, 杰克

【问题讨论】:

    标签: clojure routing routes noir


    【解决方案1】:

    与 webnoir.org 上的路线教程相比,我发现您的代码略有不同。

    你的:

    (defpage [:get "/users/:id" :id #"\d+"] {:keys [id]}
    

    webnoir:

    (defpage [:get ["/user/:id" :id #"\d+"]] {:keys [id]}
                   ^                      ^ 
    

    但也许最终没有什么不同......

    【讨论】:

      【解决方案2】:

      根据source code noir 判断,将每条路线都放入地图中,因此无法保证调度的顺序。

      在 noir.core 中:

      (defonce noir-routes (atom {}))
      ...
      (swap! noir-routes assoc ~(keyword fn-name) 
           (~action ~url {params# :params} (~fn-name params#)))
      

      稍后在 noir.server.handler 中:

      (defn add-route-middleware [rts]
        (let [ws (all-wrappers)]
                               ;Iterates over entries in a map, no particular order
          (for [[route-name route] rts] 
            (try-wrap (ws route-name) route))))
      
      (defn- pack-routes []
        (apply routes (concat (add-route-middleware @noir/pre-routes)
                              (add-route-middleware @noir/noir-routes)
                              (add-route-middleware @noir/post-routes)
                              @noir/compojure-routes)))
      

      我猜如果你有less then 16 routes noir 使用 PersistentArrayMap 并且排序被保留,但是一旦你越过这个边界,路由就会被破坏。我唯一的建议是使用明确的 URL。

      编辑:这是关于类似问题的bug report

      【讨论】:

      • 作为扩展,您可以为其提供 Compojure 路由设置,虽然它们不像 Noir 的路由那样独立,但可以保持它们的顺序。
      • Davidbe 的回答使它起作用,但是我相信 Noir 可能存在问题。我的其他控制器中的路由没有指定正则表达式,但按预期工作。
      • @Jacek 看看当前的实现,我不会依赖它。
      • @IvanKoblik 请更具体。
      • @Jacek 当然,一旦处理程序的数量大于 16,您指定处理程序的顺序将不再重要。这是因为 Clojure 在创建 {} 时默认使用 PersistentArrayMap 以保持条目与添加时相同的顺序,当条目数超过 16 时,它会自动切换到 PersistentHashMap,这将重新排序条目。这很重要,因为处理程序保存在地图中。 -> 如果您有 2 个重叠的处理程序,则有可能首先检查指定的第二个处理程序。
      猜你喜欢
      • 1970-01-01
      • 2020-09-13
      • 1970-01-01
      • 2016-08-04
      • 1970-01-01
      • 2013-11-02
      • 1970-01-01
      • 1970-01-01
      • 2019-03-16
      相关资源
      最近更新 更多