2016-04-10 6 views
1

最近私のウェブサイトのURI構造が大幅に変更され、古いページのすべてを対応する新しいページにリダイレクトする必要があります。私はすべての古い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が正しいと仮定すると、各easyハンドラの関数シンボルが必要です。私は無駄に次のことを試みた:

  1. は、配置シンボル
  2. を期待することはなく、点線リスト以外のリストを使用し、(最初のリダイレクト)を呼び出す関数シンボル
  3. を期待(gensymは)を配置します全周の準クォートと最初のリダイレクト(一次リダイレクト)

これを行うにはどうすればよいでしょうか?

+1

ハンドラを使用する代わりに、[カスタムアクセプタ](http://weitz.de/hunchentoot/#acceptor-behaviour)の作成を検討してください。そうすれば、どんな方法ででもリダイレクトを行うことができます。 – jkiiski

+0

ありがとう@jkiiski。あなたの提案は、私がやったやり方よりも良い解決策のように思えます。私はこのような解決策をいつか実現するのに十分なスキルを得ることを切望しています。 – SpyroSoft

答えて

4

推測してみましょう:DEFINE-EASY-HANDLERはマクロです。それを解決する

三つの典型的な方法:

  • コール下地層の代わりに、マクロを使用していない - の下地層は、プログラマ

  • 書き込みのために利用可能である場合、マクロを使用しますこれ

(defredirects (a . a1) (b . b1) (c . c1)))を拡大
  • 呼び出すと、各フォームのためのループでeval(またはcompilefuncall可能な場合)を使用するフォームを生成します。
+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

すでに問題を解決していますが、これを代替として追加することもできます。完全なカスタムアクセプタを作成したくない場合はHUNCHENTOOT:ACCEPTOR-DISPATCH-REQUESTにaround-methodをHUNCHENTOOT:EASY-HANDLERとして追加することができます。

は、まずはアクセプタ1ページを作ってみましょう:

(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*) 

その後/foo/bar/quuxをリダイレクト:

;; 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)) 

編集:前の方法を中心に使用してください代わりに。私は最初に、メインのメソッドを通常はどのようなロギングにも必要になると考えていました。そこで起きているが、それ以上のテストの後ではそうではないようだ。

+0

私はCLOSの部分まであなたのコードに従います。この解決策は私のものより優れていることは明らかです。ラムダを使用して、リダイレクトごとに個別の関数を作成するのではなく、名前空間が乱雑にならないようにします。また、evalとquasiquoteを使用して、Lispを可変関数名を使用するように強制することも避けています。 – SpyroSoft

+0

@SpyroSoft前のメソッドの代わりにaroundメソッドを使うようにコードを変更しました。 'ACCEPTOR-DISPATCH-REQUEST'は、hunchentootの受け手がどのような要求を行うべきかを把握するために使用するメソッドです。 aroundメソッドを定義するということは、基本的には、呼び出されるたびにこのメソッドが最初に呼び出されることを意味します。これはaroundメソッドなので、hunchentootによって定義された実際のメインメソッドを呼び出すためには(呼び出し前メソッドが自動的に呼び出す) 'CALL-NEXT-METHOD'が必要です。もちろん、リダイレクトの1つがリクエストと一致する場合は、メインメソッドを呼び出さずに早期に戻るために 'RETURN-FROM'が使用されます。 – jkiiski