Hunchentoot 重定向列表
Hunchentoot List of Redirects
我网站的 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 是正确的,它需要每个简单处理程序的函数符号。我尝试了以下无济于事:
- 将 (gensym) 放在需要函数符号的地方
- 使用列表而不是点分列表并在需要符号的地方调用(第一次重定向)
- 在整个事物周围放置一个准引号并在周围放置一个反引号(第一次重定向)
完成此任务的好方法是什么?
让我们猜猜:DEFINE-EASY-HANDLER
是一个宏。
解决该问题的三种典型方法:
调用底层而不使用宏 - 如果底层对程序员可用
编写并使用一个宏
将(defredirects (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
添加一个环绕方法。
我们先做一个受体和一页:
(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*)
然后将 /bar
和 /quux
重定向到 /foo
:
;; 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))
编辑:使用 around 方法而不是 before。我最初认为让它正常调用 main 方法对于任何 logging/etc 都是必要的。在那里发生,但经过进一步测试后似乎不是。
我网站的 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 是正确的,它需要每个简单处理程序的函数符号。我尝试了以下无济于事:
- 将 (gensym) 放在需要函数符号的地方
- 使用列表而不是点分列表并在需要符号的地方调用(第一次重定向)
- 在整个事物周围放置一个准引号并在周围放置一个反引号(第一次重定向)
完成此任务的好方法是什么?
让我们猜猜:DEFINE-EASY-HANDLER
是一个宏。
解决该问题的三种典型方法:
调用底层而不使用宏 - 如果底层对程序员可用
编写并使用一个宏
将(defredirects (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
添加一个环绕方法。
我们先做一个受体和一页:
(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*)
然后将 /bar
和 /quux
重定向到 /foo
:
;; 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))
编辑:使用 around 方法而不是 before。我最初认为让它正常调用 main 方法对于任何 logging/etc 都是必要的。在那里发生,但经过进一步测试后似乎不是。