Common lisp Hunchentoot重定向列表

Common lisp Hunchentoot重定向列表,common-lisp,hunchentoot,Common Lisp,Hunchentoot,我的网站的URI结构最近发生了巨大变化,我需要将所有旧页面重定向到相应的新页面。我有一个所有新旧URI成对的虚线列表。目前,我正在尝试为循环中的每个对象定义简单的处理程序: (let ((redirects '(("/old/uri/example-1" . "/new/uri/example-1")))) (dolist (redirect redirects) (hunchentoot:define-easy-handler (???? :uri (first redirect)

我的网站的URI结构最近发生了巨大变化,我需要将所有旧页面重定向到相应的新页面。我有一个所有新旧URI成对的虚线列表。目前,我正在尝试为循环中的每个对象定义简单的处理程序:

(let ((redirects '(("/old/uri/example-1" . "/new/uri/example-1"))))
  (dolist (redirect redirects)
    (hunchentoot:define-easy-handler (???? :uri (first redirect)) ()
       (redirect (rest redirect)))
    ))
也许有更好的办法。假设define easy handler是正确的,则每个easy handler都需要一个函数符号。我尝试了以下方法,但无效:

  • 将(gensym)放置在需要函数符号的位置
  • 使用列表而不是虚线列表,并在需要符号的地方调用(第一个重定向)
  • 在整件事情周围放置一个准引号,在周围放置一个非引号(第一个重定向)

  • 实现这一点的好方法是什么?

    让我们猜猜:
    DEFINE-EASY-HANDLER
    是一个宏

    解决这一问题的三种典型方法:

    • 如果底层可供程序员使用,则调用底层,不要使用宏

    • 编写并使用一个宏

    (defreirects(a.a1)(b.b1)(c.c1))
    展开为

    (progn
      (hunchentoot:define-easy-handler (f-a ... a) () (... a1))
      (hunchentoot:define-easy-handler (f-b ... b) () (... b1))
      (hunchentoot:define-easy-handler (f-c ... c) () (... c1)))
    
    • 生成要调用的表单,并在每个表单的循环中使用
      eval
      (或
      compile
      funcall
      ,如果可能)

    此解决方案有效。我非常感谢关于这是否是最佳实践的反馈

    (defun add-redirect (name from to)
      (eval `(hunchentoot:define-easy-handler (,name :uri ,from) ()
        (redirect ,to))))
    
    (defun add-redirects (redirects)
      (dolist (redirect redirects)
        (add-redirect (first redirect) (second redirect) (third redirect))
        ))
    
    (add-redirects
     '(
       (redirect-1 "/redirect-1/" "/destination-1/")
       (redirect-2 "/redirect-2/" "/destination-2/")
       (redirect-3 "/redirect-3/" "/destination-3/")
       ))
    

    虽然你已经解决了这个问题,但我想我可以添加这个作为替代。如果您不想创建一个完整的自定义接受程序,可以在
    HUNCHENTOOT:acceptor-DISPATCH-REQUEST
    上为
    HUNCHENTOOT:EASY-HANDLER
    添加一个around方法

    让我们先做一个接受者和一页:

    (defparameter *acceptor* (make-instance 'hunchentoot:easy-acceptor :port 4242))
    
    (hunchentoot:define-easy-handler (foo :uri "/foo") ()
      (format nil "<html><body><h1>Test</h1><p>foo</p></body></html>"))
    
    (hunchentoot:start *acceptor*)
    

    编辑:使用around方法而不是before。我最初认为,让它调用主方法通常是必要的任何日志记录等发生在那里,但经过进一步的测试,它似乎不是。

    你可能想考虑创建一个替代使用简单的处理程序。这样你就可以随心所欲地重定向。谢谢@jkiiski。你的建议似乎比我做的更好。我渴望有一天获得足够的技能来实施这样的解决方案。感谢您提供的可用选项列表。请看下面我的解决方案。结果证明,让我感到困惑的是函数定义本身。当我试图使用一个符号时,我得到了错误“函数名不合法”。我不知道如何生成函数符号?我甚至不确定这是不是正确的术语。太棒了。我跟踪你的代码直到CLOS部分。很明显,这个解决方案比我的好。它使用lambdas来避免名称空间混乱,而不是为每个重定向创建单独的函数。它还避免了使用eval和quasikote强制Lisp使用变量函数名。@SpyroSoft我将代码改为使用around方法而不是before方法
    ACCEPTOR-DISPATCH-REQUEST
    是hunchentoot接受者用来确定如何处理请求的方法。为它定义一个around方法基本上意味着每次调用该方法时都会首先调用它。由于这是一个around方法,因此需要调用hunchentoot定义的实际main方法(在方法自动调用它之前)。当然,如果其中一个重定向与请求匹配,
    RETURN-FROM
    用于提前返回,而不调用main方法。
    ;; A simple helper to create prefix dispatchers.
    (defun make-redirect-list (redirects)
      (mapcar (lambda (redirect)
                (destructuring-bind (from . to) redirect
                  (hunchentoot:create-prefix-dispatcher from
                                                        (lambda ()
                                                          (hunchentoot:redirect to)))))
              redirects))
    
    (defparameter *redirects* (make-redirect-list
                               '(("/bar" . "/foo")
                                 ("/quux" . "/foo"))))
    
    (defmethod hunchentoot:acceptor-dispatch-request :around
        ((acceptor hunchentoot:easy-acceptor) request)
      (dolist (redirect *redirects*)
        ;; Match the request against the prefix dispatchers in *REDIRECTS*...
        (let ((handler (funcall redirect request)))
          (when handler
            ;; and call the corresponding handler if a match is found.
            (return-from hunchentoot:acceptor-dispatch-request
              (funcall handler)))))
        ;; Unless a handler was found, call next method to 
        ;; handle the request normally.
      (call-next-method))