Hunchentoot Список перенаправлений
Структура 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) там, где ожидается символ функции
- Использование списков, а не пунктирных списков и вызов (первое перенаправление), где он ожидает символ
- Размещение квазицитаты вокруг всего и кавычки вокруг (первый редирект)
Что было бы хорошим способом сделать это?
3 ответа
Давайте догадаемся: 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
если возможно) в цикле для каждой формы.
Хотя вы уже решили проблему, я решил добавить ее в качестве альтернативы. Если вы не хотите делать весь пользовательский акцептор, вы можете добавить метод 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))
Изменить: использовать метод вокруг, а не раньше. Первоначально я полагал, что для любого ведения журнала и т. Д. Было бы необходимо, чтобы он вызывал метод main как обычно. происходит там, но после дальнейших испытаний, похоже, нет.
Это решение работает. Я определенно ценю отзывы о том, является ли это лучшей практикой.
(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/")
))