2016-04-10 2 views
1

Структура URI моего веб-сайта сильно изменилась в последнее время, и мне нужно перенаправить все старые страницы на соответствующие им новые страницы. У меня есть пунктирный список пар всех старых и новых URI. В настоящий момент я пытаюсь определить простые обработчики для каждого в цикле:Список переадресаций Hunchentoot

(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. Размещения quasiquote вокруг всего этого предмета и недокачка вокруг (первая переадресация)

Что было бы хорошим способом для этого?

+1

Возможно, вы захотите рассмотреть возможность создания [пользовательского акцептора] (http://weitz.de/hunchentoot/#acceptor-behaviour) вместо использования простых обработчиков.Таким образом, вы можете делать перенаправления так, как хотите. – jkiiski

+0

Спасибо @jkiiski. Ваше предложение кажется лучшим способом решить его, чем так, как я. Я стремлюсь получить достаточно навыков для реализации такого решения. – SpyroSoft

ответ

4

Предположим: 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, если это возможно) в цикле для каждой формы.
+0

Благодарим вас за список доступных вариантов. См. Мое решение ниже. – SpyroSoft

0

Это решение работает. Я определенно ценю отзывы о том, является ли это лучшей практикой.

(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/") 
    )) 
+0

Оказывается, что меня выбрасывало определение самой функции. Я получал ошибку «Не легально как имя функции:», когда я пытался использовать символ. Я не уверен, как создать символ функции? Я даже не уверен, что это правильная терминология. – SpyroSoft

1

Хотя вы уже решили проблему, я решил, что могу добавить это в качестве альтернативы. Если вы не хотите создавать целый пользовательский акцептор, вы можете добавить метод around на 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)) 

Edit: Используйте вокруг метода вместо ранее. Первоначально я полагал, что разрешить ему вызов основного метода, как правило, необходимо для любого ведения журнала/etc. происходит там, но после дальнейших испытаний это не похоже.

+0

Удивительный. Я следую вашему коду до части CLOS. Очевидно, что это решение лучше, чем мое. Он использует лямбда, чтобы избежать загромождения пространства имен, а не создавать отдельные функции для каждой из переадресаций. Он также избегает использования eval и quasiquote для принуждения Lisp к использованию имен переменных функций. – SpyroSoft

+0

@SpyroSoft Я изменил код, чтобы использовать метод around, а не метод before. «ACCEPTOR-DISPATCH-REQUEST» - это метод, который используют акцепторы hunchentoot, чтобы выяснить, что делать с запросами. Определение вокруг метода для него в основном означает, что этот метод будет вызываться первым при каждом его вызове. Так как это метод, метод «CALL-NEXT-METHOD» необходим для вызова фактического основного метода, определенного hunchentoot (ранее методы вызывали его автоматически). Конечно, если одно из перенаправлений соответствует запросу, 'RETURN-FROM' используется для возврата раньше, не вызывая основной метод. – jkiiski

Смежные вопросы