Common Lisp Webアプリケーションの開発(パート3)

このレビューは、彼らのスタートアップの未来をこの素晴らしい言語に委ねることを決定(または決定)する人々のための小さなガイドです。 主にウェブ開発に重点が置かれるという事実にもかかわらず、私はCommon Lispに関連する何らかの一般的なトピックもカバーしようとします。 資料は、 AlterMoby自身のWeb開発経験から収集されます。

このレビューの3番目の部分は、Hunchentoot Webサーバーに当てられます。 そのアーキテクチャと基本機能を検討してください。 さらに、いくつかの関連する問題、特にHTML / XMLの生成に触れます。

画像

Webサーバーの選択


このレビューの最後の部分で最小限のLispシステムをデプロイした後、Webサーバーを選択します。 この質問は明らかではありません-同じCLikiは7つの異なるライブラリへのリンクを提供します。 仕事用にWebサーバーを選択したとき、いくつかの要因から進めました。 まず、CLコミュニティで広く知られ、幅広い愛好家に支えられ、最新のものでなければなりません。 第二に、少なくとも1つの有望なWebフレームワークがそれに基づいている必要があります。 さらに、それに基づいて商業的に成功したサイトの可用性を確認することをお勧めします。 これらの基準に基づいて、2つの製品(Portable AllegroServとHunchentoot)だけが私の視野に入ってきました。

ポータブルAllegroServは、Allegro CL専用に作成されたオリジナルのWebサーバーであるAllegroServのバージョンです。 後者のソースコードは、ネイティブコンパイラの非標準の拡張機能を使用するため、Common Lispと互換性がありません。 実際のところ、AllegroServの作成者は最大の効率を達成しようとしたため、厳密な基準からの逸脱を余儀なくされました。 その結果、高速でエレガントなWebサーバーができました。これは、おそらく今日のAllegro CLにとって最適な選択肢です。 AllegroServのソースコードはLLGPLライセンスの下でリリースされたため、標準のCommon Lispにそれを適合させた愛好家がいました。 得られた製品は、Portable AllegroServと呼ばれていました。 一部のリスパーによれば、後者はパフォーマンスと信頼性の両方において、オリジナルよりも劣っています。

レビューのこの部分の主役である、奇妙な名前のHunchentootを持つWebサーバーは、最初は標準のCommon Lispによってガイドされていました。 「すぐに使える」ので、ほとんどの一般的なコンパイラで動作します。 私にとって、Hunchentootを支持する重要な議論は、有望なWebフレームワークWeblocksに基づいているという事実でした 。 プロジェクトでこのフレームワークを使用することを最終的に拒否したという事実にもかかわらず、Hunchentootは私を全く失望させませんでした。 次に、この素​​晴らしい製品の構造と機能を検討します。

Hunchentootの紹介


まず、Hunchentootをインストールしたことを確認してください。

( asdf:oos 'asdf:load-op :hunchentoot )

次に、 アクセプタークラスのインスタンス(httpリクエストレシーバー)を作成して実行します。

( hunchentoot:start ( make-instance 'hunchentoot:acceptor :port 8080 ))

Hunchentootがhttps要求を受け入れることができるように、証明書とキーファイルの指定を忘れずに、 「acceptor 「ssl-acceptor (その子孫) に置き換える必要があります。

Hunchentootヘルプから取得した最も単純なハンドラーを考えてみましょう。

( hunchentoot:define-easy-handler ( say-yo :uri "/yo" ) ( name )
( setf ( hunchentoot:content-type* ) "text/plain" )
( format nil "Hey~@[ ~a~]!" name ))


このハンドラーはsay-yoと呼ばれ、URL / yoにバインドし、単一の名前パラメーターを取得します(GETまたはPOST経由)。 ハンドラーは、「Hey name!」を含むテキストドキュメントを生成します。nameはnameパラメーターの値、またはnameパラメーターが指定されていない場合(つまり、nil)は単に「Hey!」です。 複雑な文字列フォーマットに混乱している場合は、 フォーマット関数ディレクティブを確認してください。 / yoおよび/ yo?に移動して、このハンドラーの動作を確認しますか?Name = Vasia。

テキストの代わりに、ハンドラーは目的のファイルを提供できます。

( hunchentoot:define-easy-handler ( get-file :uri "/file" ) ( name )
( handle-static-file ( format nil "/home/me/folder/~a" name ))


原則として、この機能は小さなアマチュアクラフトを作成するのに十分なはずです。 より深刻な作業では、マクロdefine-easy-handlerを放棄し、リクエストをディスパッチするメカニズムを理解する必要があります。 後者の主な機能の概要を説明します。

アクセプタークラス(およびssl-acceptorクラス )の各インスタンスには、 リクエストマネージャーがあります。 リクエストマネージャーは、 リクエストクラスのインスタンス(httpリクエスト)を受け取り、出力httpストリーム(HTML / XMLまたはバイナリデータ)を返す関数です。 出力ストリームは指定されたURLに依存するため、実際には、クエリマネージャーはそれを生成せず、このロールを委任する適切なハンドラーを検索します。 デフォルトでは、Query Managerはディスパッチ関数を含む* dispatch-table *リストをスキャンします 。 各スケジューリング関数は、要求オブジェクトを受け入れ、その基準に従って分析し、一致する場合はハンドラーを返します。出力ストリームを生成する関数です(一致しない場合はnilを返します)。 したがって、標準リクエストマネージャは、ディスパッチ関数の1つがハンドラーを返すまでディスパッチ関数を開始します。 * dispatch-table *の最後に 、通常default-dispatcherがあります -常にハンドラーを返すディスパッチ関数です(デフォルトでは、これはページが見つからないというメッセージです)。

上記のスケジューリング方式はやや複雑に見えるかもしれませんが、実際には、そのような構造は大きな柔軟性を可能にします。 特に、ハンドラーリターンアプローチを使用すると、エレガントなディスパッチ関数を作成できます。 define-easy-handlersマクロによって作成されたディスパッチハンドラーは、次の標準スキームを使用します* dispatch-table *dispatch-easy-handlersディスパッチ関数を含みます。 後者は、単純化されたディスパッチャを実装し、独自の内部リストを調べます。 このリストには、 define-easy-handlers定義されたすべてのハンドラーの説明が含まれています 。 したがって、スケジューリングは、ハンドラーを選択するための独自のロジックを持つ多くの独立したブランチに分割できます。

Hunchentootは、標準的なディスパッチ関数のいくつかのジェネレーターと、いくつかの標準的なハンドラーを定義しています 。 たとえば、指定れたURLプレフィックスおよびハンドラーによるcreate-prefix-dispatcherは、URLリクエストが指定されたプレフィックスに準拠しているかどうかをチェックするディスパッチ関数を生成します。 create-regex-dispatcher関数は前のものと似ていますが、URLを特定の正規表現パターンにマッピングするディスパッチ関数を生成します。 create-folder-dispatcher-and-handler関数は、URLプレフィックスとディレクトリパスを受け入れ、指定されたディレクトリからファイルを配布するディスパッチ関数を返します。 標準ハンドラには、get-fileの定義で使用したhandle-static-fileが含まれます。

Common Lispの柔軟性により、オンザフライで既存の関数とメソッドを再定義できます。これは、Hunchentootの柔軟性に貢献せざるを得ません。 この方法では、 アクセプタクラスの新しい子孫を作成できるだけでなく、上記のハンドラ検索スキームを完全に放棄することでデフォルトのディスパッチャをオーバーライドしたり、リクエスト処理ロジックを完全に変更したりできます。 たとえば、私のプロジェクトに取り組む過程で、Hunchentootに、データをダウンロードするプロセス中に、マルチパート/フォームデータリクエストの形式をチェックさせ、完全に受け入れた後ではありません。 これにより、DoS攻撃中に多くのマシンがマルチメガバイトのガベージをサーバーに送信する状況を回避できます。

強力で最新のWebサーバーとして、Hunchentootは多くの標準機能をサポートしています。 これらには、Cookieのサポート、便利なデバッグとロギングなどが含まれます。 Webページでこの機能の説明を見つけることができます。

HTML / XML生成


レビューのこの部分を締めくくるために、HTML / XMLを生成するためのシンプルで便利なDSLを定義するCL-WHOライブラリを検討してください。 いつものように、一度見たほうがいいです:

( push :tag3 *html-empty-tags* )
( with-html-output-to-string ( http-stream )
( :tag1 :attr1 1 :attr2 "2"
( :tag2 :attr3 ( + 1 2 ))
( loop for i from 1 to 3 do
( with-html-output ( http-stream )
( :tag3 :attr4 ( when ( oddp i ) "odd" ))))))


この構造の結果は直観と矛盾しません:

"<tag1 attr1='1' attr2='2'><tag2 attr3='3'></tag2>
<tag3 attr4='odd' /><tag3 /><tag3 attr4='odd' /></tag1>"


ご覧のとおり、 with-html-output-to-stringマクロは、このs-expressionに対応する開始タグと終了タグからXMLコンストラクトを構築します。 最初のコマンドは、単一タグのリストにtag3タグを追加します。 このようなタグの場合、添付ファイルがない場合、終了タグは生成されません。 次に、 with-html-output-to-stringマクロが呼び出されます。これは、メインCL-WHOマクロであるwith-html-outputのラッパーです。 この例からわかるように、任意の制御構造を使用してコード生成を自動化できます。

結果の文字列はXMLモードで作成されました。 このモードでは、XML / XHTMLドキュメントを生成する価値があります。 HTMLを使用する場合は、空のタグに終了スラッシュが含まれないSGMLモードがあり、属性には値がなくてもかまいません。 Hunchentootの場合のように、CL-WHOをさらに詳しく紹介するために、Webページに送ります。

Source: https://habr.com/ru/post/J106067/


All Articles