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 верен, для каждого простого обработчика требуется символ функции. Я попробовал следующее безрезультатно:

  1. Размещение (gensym) там, где ожидается символ функции
  2. Использование списков, а не пунктирных списков и вызов (первое перенаправление), где он ожидает символ
  3. Размещение квазицитаты вокруг всего и кавычки вокруг (первый редирект)

Что было бы хорошим способом сделать это?

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/")
   ))
Другие вопросы по тегам