こんにちは、Habr! あなた自身、隣人、または彼女の犬のためにサイトを作りたいと長い間望んでいたが、まだそれをしていないなら、この記事はあなたのためです! このシリーズの記事では、例として単純なブログを使用してサイトを作成するためにバイブで作業する基本を紹介します。
最初の部分では、基本的なポイントを分析し、結果のアプリケーションに暗号化を追加します。
0.最初から始めましょう
- dmdをインストールする
- ダブをインストールする
- 次のコマンドでvibeを使用してプロジェクトを作成します
mkdir yourblogname
cd yourblogname
dub init -t vibe.d
作成されたアプリケーションに関するダブの追加質問が送られます。 ほとんどのフィールドにはデフォルト値がありますが、jsonよりも読みやすく、シンプルであり、オプションも同じであるため、sdl形式を選択することをお勧めします。
1.シンプルなWebアプリケーション
そのため、すでにLudwigのブランクがあり、それを拡張する必要があります。 最初に行うことは、アプリケーションのクラスを作成し、いくつかのページを追加することです。
import vibe.d; shared static this() { auto settings = new HTTPServerSettings; settings.port = 8080; settings.bindAddresses = ["::1", "127.0.0.1"]; auto router = new URLRouter; // router.registerWebInterface(new MyBlog); // router.rebuild(); // =) listenHTTP(settings, router); // } class MyBlog { @path("/") void getHome(scope HTTPServerRequest req, scope HTTPServerResponse res) { res.writeBody("Hello, World! <a href='/page2'>go to page2</a>", "text/html; charset=UTF-8"); } void getPage2(scope HTTPServerRequest req, scope HTTPServerResponse res) { res.writeBody("Page2 <a href='/'>go to index</a>", "text/html; charset=UTF-8"); } }
ご覧のとおり、 getHome
メソッドにはUDA @path("/")
があり、これがルートページであることを示しています。 UDA-ユーザー定義属性-ユーザーが宣言した属性。 実際、これらは言語のオブジェクトです:列挙型、構造体、単純なデータ型。 UDAを持つエンティティを使用して、属性の存在とその値を確認し、UDAでマークされたクラス/構造内のすべてのフィールドとメソッドを取得することもできます。 この場合、vibeはこれを使用して宛先コードを作成します。 getPage2
メソッドは命名規則を使用し 、パスhttp://127.0.0.1:8080/page2
沿ってgetリクエストで実行しhttp://127.0.0.1:8080/page2
。 @property
メソッドも同じように動作します。 メソッドのシグネチャはテンプレートのhello
関数と変わらないため、ページの本文を手で記述します。 面倒ではなく、ビューをviews
フォルダに追加し、すぐに心に追加します。
いくつかのファイルを作成しましょう:
サイトのすべてのページのテンプレート。
doctype html html head // head block head // title , head title #{title} body header // div, '<div class="mrow">' .mrow // views/header.dt include header main .mrow // main block main footer .mrow // views/footer.dt include footer
コメントのインデントは、ブロックのインデントに対応する必要があります。 コメントは結果のhtmlに分類されます。必要ない場合は// -
(マイナス記号付き)を使用してください。
サイトヘッダーがあります
div
地下室があります
div ,
メインページ、最初の行は、どのテンプレートを展開するかを示します(同じフォルダ内にあり、 .dt
拡張子がないため、パスはありませ.dt
)
extends layout block head // , // , D , - auto title = ""; block main // - html, div a(href="/page2")
2番目のページはメインに似ています
extends layout block head - auto title = " "; block main div 2 a(href="/")
ブログのコードを修正します
class MyBlog { @path("/") void getHome() { render!("index.dt"); } void getPage2() { render!("page2.dt"); } }
簡潔になり、回答の本文を直接書く必要がなくなりました。 スタイルを追加!
* { margin: 0; padding: 0; } body { font-family: sans-serif; font-size: 13px; text-align: center; width: 100%; } .mrow { margin: 0 auto; width: 1170px; text-align: left; } header { height: 60px; width: 100%; background: #e2e2e2; border-top: none; border-right: none; border-left: none; border-bottom: 1px solid; border-radius: 0; border-color: #aaa; margin-bottom: 20px; font-size: 24px; } header div { padding-top: 10px; } main { margin-top: 10px; } footer { height: 60px; width: 100%; background: #333; color: #bbb; position: absolute; margin-top: 20px; padding: 0; bottom: inherit; border-top: 2px solid #888; } footer div { padding-top: 10px; }
アプリケーションで静的ファイルの配布を有効にする必要があります
shared static this() { ... router.get("*", serveStaticFiles("public/")); ... }
最後に、 layout.dt
先頭にスタイルを追加します
... html head link(rel="stylesheet", href="style.css") ...
組み立てて起動すると、次のようになります。
そうではありませんが、 私の目が落ちないことと、これで作業することがより快適になることを願っています )
2.安全にしましょう
私たちには何らかの基盤がありますが、今はさらなる開発について考える時です。 そして、機能を追加する前に、セキュリティを管理します。暗号化を追加します。 たとえば 、証明書の作成に関する多くの情報を見つけることができます。 説明のない主な手順は次のとおりです。
ルートキー
openssl genrsa -out rootCA.key 2048
ルート証明書
openssl req -x509 -new -key rootCA.key -days 9999 -out rootCA.crt
質問への回答は重要ではありません。ブラウザが彼を信頼するようにします)
別のキー
openssl genrsa -out server.key 2048
証明書要求(ドメイン名を指定することが重要です)
openssl req -new -key server.key -out server.csr
新しい証明書に署名する
openssl x509 -req -in server.csr -CA rootCA.crt -CAkey rootCA.key -CAcreateserial -out server.crt -days 9998
ブラウザにrootCA.crt
を追加し、 rootCA.key
秘密にします。
次に、アプリケーションで暗号化を有効にします。
shared static this() { ... settings.tlsContext = createTLSContext(TLSContextKind.server); settings.tlsContext.useCertificateChainFile("server.crt"); settings.tlsContext.usePrivateKeyFile("server.key"); ... }
これで、すべてを正しく行った場合、サイトはhttp
経由でアクセスできなくなり、質問なしでhttps
経由でアクセスできるようになりhttps
。
3.最も単純な承認
まず、アプリケーションでセッションを作成します。
shared static this() { ... settings.sessionStore = new MemorySessionStore; ... }
いくつかのコードを追加します。 クラスの外部には、セッション変数のタイプがあります。
struct UserSettings { bool loggedIn = false; string email; }
複雑な認識のためには、おそらく新しいクラス全体を表示する方が良いでしょう。
class MyBlog { mixin PrivateAccessProxy; private SessionVar!(UserSettings, "settings") userSettings; // // _error @path("/") void getHome(string _error) { auto error = _error; auto settings = userSettings; render!("index.dt", settings, error); } /+ @errorDisplay , msg getHome, _error, @auth , , , , auth, , , , , email +/ @auth @errorDisplay!getHome void getWritepost(string _email) { auto email = _email; render!("writepost.dt", email); } // ValidEmail string, @errorDisplay!getHome void postLogin(ValidEmail email, string pass) { enforce(pass == "secret", " "); // userSettings = UserSettings(true, email); // redirect("./"); } void postLogout(scope HTTPServerResponse res) { userSettings = UserSettings.init; res.terminateSession(); redirect("./"); } private: /+ ensureAuth, ensureAuth _email +/ enum auth = before!ensureAuth("_email"); /+ , , email +/ string ensureAuth(scope HTTPServerRequest req, scope HTTPServerResponse res) { if (!userSettings.loggedIn) redirect("/"); return userSettings.email; } }
クラスのすべてのパブリックメソッドはルーティングに分類されるため、 ensureAuth
private
として作成されます。 同時に、バイブは@auth
でマークされたメソッドの前にこのメソッドを呼び出すためにこのメソッドについて知る必要があるため、 mixin PrivateAccessProxy
を使用する必要があります。 @auth
属性は、フックとして機能するbefore
テンプレートを使用して作成され、マークされた関数の前に指定された関数を呼び出し、フック関数の結果を引数として渡します。 @after
もあります。これは、関数を強制的にafterに実行し、フラグ付きの結果を引数として受け入れるためにフック関数を必要とします。 残念ながら、vibe Webサイトにはドキュメントが見つかりませんでしたが、コードにはこれらのポイントに関するドキュメントがあります。 また、page2メソッドの名前を変更(削除)しました。 GetWritepostはそれを置き換え、新しいレコードを作成するためのページを返します。
残りのファイルもわずかに変更する必要があります。
エラー
block error
表示を含むviews/layout.dt
ブロックを挿入しblock error
(レイアウトでは他のファイルから挿入されます)
views/index.dt
にエラー表示ブロックを追加すると、次のようになります
... block error - if (error.length) div#error #{error} ...
ご存知のように、Dのコードは「-」記号の後に行く必要があり、
#{value}
エスケープして、値変数の値をhtmlに貼り付けます。
ファイル
views/logindesk.dt
作成し、ログイン用のフォームを追加します
div form#loginform(action="/login", method="POST") div input(class="form-control",name="email",placeholder="Email",type="email",required) div input(class="form-control",name="pass",placeholder="",type="password",required) div button(type="submit")
インデントに注意する必要があります。それらはpythonのように機能します(そして、ここでフォーマットすると時々スペースが消費されます)。
views/index.dt
、メインブロックを変更します
... block main - if (!settings.loggedIn) include logindesk - else div
settings
とerror
変数は、render!("index.dt", settings, error);
関数でテンプレートに渡されますrender!("index.dt", settings, error);
getHome
メソッドで。 各プレゼンテーションテンプレートは、独自の変数セットを受け入れます。
-
views/writepost.dt
まだ何もしないフォームを書きviews/writepost.dt
extends layout block head - auto title = " "; block main div #{email} form#postform(action="/posts", method="POST") div input(class="from-control", name="title") div textarea(class="form-contorl", name="text") div button(type="submit")
- あなたの裁量で「新しい投稿」と「ホーム」へのリンクを作成します。
- このすべてを自分の裁量でスタイルするために(最後に最終形式でコードをレイアウトします)
これで、ログインできるサイトがあり、ログインしていないとアクセスできないページ(writepost)があります。
4.最も単純なブログエントリ
記事は非常に膨大であることが判明しましたが、何らかの論理的なコンマに持っていきたいです)
新しい記事のレコードを通常のクラスフィールドに追加すると、フィールドタイプは構造の配列になります
struct Post { string author; string title; string text; }
この配列をクラスに追加し、パラメーターでgetHome
メソッドのrender
関数にgetHome
、これらの投稿を配列に書き込むメソッドを追加します。
class MyBlog { ... public: Post[] posts; @path("/") void getHome(string _error) { ... render!("index.dt", posts, settings, error); } ... // getWritepost @auth @errorDisplay!getWritepost void postPosts(string title, string text, string _email) { posts ~= Post(_email, title, text); redirect("./"); } ... }
注意してください-メソッドパラメータの名前はフォームフィールドの名前と一致する必要があります! 主な変更は残ります。これにより、投稿を確認できます。 views/index.dt
、エントリ「Content」をコードviews/index.dt
置き換えます
... - if (!settings.loggedIn) include logindesk - else - foreach(post; posts) div.post div.title #{post.title} div.text #{post.text} div.author #{post.author}
ここまでで、次のようなアプリケーションをすでに作成しているはずです。
- 承認の最も簡単な形式
- トラフィック暗号化
- 認可チェック
- 投稿の追加と表示
次のようになりました。
この部分のソースコードはこちらです。
次のパートでは、mongoの使用方法、投稿用ページの作成方法(URLに投稿のインデックスまたは名前が含まれる)、およびコメントについて説明します。
完全に明確ではなかったとコメントに書いてください。この部分を完成させてうれしいです。