今日は、ポータル
http://www.abbyyonline.comの例を使用して、分散された異種の、時には非常に深刻で可変的にロードされるインターネットアプリケーションについて説明し
ます 。 特定のプラットフォームに関連する技術的な詳細には触れないようにします。説明したアプリケーションの主要部分はASP.Net MVCに実装されていますが、この資料は、使用するツールに関係なく、Web開発に関係するすべての人にとって興味深いものです。
自分を尊重し、自分の職業を愛し、それから真の喜びを得る各開発者は、次のプロジェクトに進み、完璧なアプリケーションの作成に努めます-最高の、優れた拡張可能なアーキテクチャと美しいコード...そして、2つの根本的な問題が常にこれを妨げます:
- 私たちの周りの世界の不完全さ
- ビジネス要件
プロジェクトAbbyyOnlineはまた、毎ターンそれらに対処しなければなりませんでした。 この場合、世界の不完全さは、AbbyyOnline(またはその内部名ではAOL)がWebアプリケーションであり、不完全な世界では、そのようなアプリケーションはネットワーク機能によって制限されたステートレス(つまり、ステートレス)で支えられていることです(レイテンシ、帯域幅)、ブラウザの蛇行に適応することを余儀なくされ、クライアントスクリプト、バイト、フラッシュ、サーバーコード、次のダイヤラーなど、テクノロジーの動物園全体で実装される運命にあります SQLプロジェクト。
ビジネスも劣らない...マーケティングの考えによれば、ABBYYがオンラインで提供するすべてのサービスがこのポータルに表示されるように、AOLはインターネット上の会社全体の顔になるはずです。
ABBYYにはかなり明確なポジショニングがあります。これらは言語、認識、それに関連するすべてのもの、つまり、何らかの形でのワードプロセッシングです。 当然、オンラインサービスを統一戦線として提供したかったのです。 合理的ですか? 確かに、しかしこれは実際にはどういう意味ですか? 少なくとも、単一のユーザーベースが必要です。シングルサインオン認証を実装する必要があります。つまり、ユーザーが1つのサービスにログオンしている場合、残りは不必要な質問をせずに直接認識する必要があります。統一された設計要素と論理要素が必要です。
すべては問題ありませんが、すべてのオンライン企業サービスは個別のかなり深刻なアプリケーションです。 また、これらのアプリケーションは異なるサーバーでホストされるだけでなく(一部のアプリケーションは物理的に複数のサーバーに配置され、非常に深刻なインフラストラクチャを必要とします)、さまざまな理由で異なるサイトに配置されます。 歴史的にこれらのサーバーには異なるオペレーティングシステムが搭載されていたという事実は言うまでもありません(詳細に興味があるなら、WindowsサーバーとFreeBSDがあります)。 一般的に、真に異種の分散システム-この背景に対して、異なるポータルサイトの異なるドメイン名などの些細なことは、すでに無視することができます。
一般的な構造
これらのタイプのポータルを作成する場合、非常に多くのデータとページが共有され、これらすべてを接続サイトである中央サイトに配置するのが論理的です。 私たちの場合、中央サイトのタスクは認証、共有ページの操作、共有リソースの操作です。 この中央サイトにはWebService APIが装備されており、これを介してサービスの提供を含むタスクを行う他のサイトは、ポータルの一般的なインフラストラクチャと連携できます。たとえば、現在のユーザーに関する完全な情報を受け取ったり、オンラインストアの共通バスケットに商品を入れたりできます。 サービスサイトはお互いについて何も知らず、メインポータルサイトの存在を疑うだけで、上記のAPIを使用できます。
シングルサインオンとクロスドメイン認証
最初の問題は、シングルユーザーベースとシングルサインオン認証です。ここでの難しさは何ですか? すでにわかったように、Webアプリケーションの機能の1つは状態の欠如です。 実際には、これは、ブラウザーからサーバーへのすべての要求が前の要求に依存せず、サーバーが「誰が来たのか」を推測しなければならないことを意味します。 従来、この問題は特別な認証Cookieを記述することで解決されていました。ブラウザは、Cookieが期限切れになるまで、リクエストごとにサーバーに送信します。 しかし、実際には、セキュリティ上の理由から、サイトのサーバー部分は同じ第2レベルドメインに記録されたCookieのみを読み取ることができます。たとえば、
http://finereader.abbyyonline.comに展開されたサイトはサイトが書き込んだCookieを読み取ることができます
http://www.abbyyonline.comにデプロイされてい
ますが、サイト
http://finereaderonline.comは、どのような状況でもそのようなCookieを読み取りません。 ただし、タスクの条件に応じて、ポータルのさまざまな部分をさまざまなドメインに配置できるため、ある種のクロスドメイン認証メカニズムが必要です。
原則として、この問題を解決するには主に2つの方法があります。リダイレクト(.Net PassportやOpenID、LiveIDなどのようなもの)と、GoogleやYandexのようなjavascriptがサービスで行います。 リダイレクトスキームは、おおよそ次のように機能します。
ポータルサイトのページにアクセスする場合、このユーザーのポータルが知っているかどうかを確認する必要があります。 安全なページだけでなく、どのページにもアクセスできるのはなぜですか? ニックネーム、プロファイルへのリンク、およびその他の個人情報の一部をすべてのページに表示する必要があるため、ユーザーは私たちが彼を覚えており、彼に会えてうれしいことを知っています:)
この目標を達成するために、次の一連のアクションを実行します。
- サイトは、独自の本番の認証Cookieを読み取ろうとしています。 これが成功した場合、認証プロセスはここで終了します。そのようなCookieがある場合、ユーザーが初めてここにいないことを意味し、このサイトでユーザーを正常に識別したためです。
- サイトは、認証プロセスは実行されたが成功しなかったという特別なCookieを読み取ろうとしています。 これが成功した場合、ここで終了することもできます-このユーザーを知らないことがわかります。
- 前の段落が失敗した場合、...
- サイトは特別な一意のトークンを作成します
- データベースのネームプレートに、特に認証を要求したページのトークンとURLを含むエントリが作成されます。
- このサイトは特別なCookieを作成します。これは、これまでのところこのユーザーを知らないが、認証要求をすでに送信していることを示しています。 このCookieの役割は、ユーザーが匿名ユーザーであることを示す通常の認証Cookieによって果たされる可能性があります。この場合、段落番号2は必要ありません。
- サイトは、リクエストを特別な中央サーバーのURLにリダイレクトし、リクエスト行に同じトークンを渡します。
- このようなリクエストを受け取った中央サーバーは...
- ユーザーから認証Cookieの読み取りを試みます。
- データベース内で、クエリ文字列で転送されたトークン上の同じ実際のタブレットで、目的のレコードを見つけ、前の段落からの操作の結果をそこに書き込みます。
- 中央サーバーは、認証をリクエストしたサイトにリダイレクトし、リクエスト行に同じトークンを含む特別なURLにリダイレクトします
- この特別なURLのリクエストを受け取ったサイトは、すべてのポータルサイトにあるはずです...
- 彼は認証プロセスに関するCookieを読み取ろうとしています(3cで記述しました)。それが不可能な場合、クライアントはCookieの記録をサポートせず、Cookieなしでは動作できません。したがって、わかりやすいホームページにユーザーを送信する必要があります。この嘆かわしい事実を彼に思い起こさせます。
- データベースに登ると、すべてが同じテーブルにあり、トークンによって認証結果を中央サーバーから読み取ります。
- 中央サーバーによる認証が成功した場合、次回ユーザーが無駄にならないように、中央サーバーは認証Cookieを書き留めます。
- 認証プロセスを開始したページにリダイレクトします。
AOLで認証を実装する場合、上記の方法で行った結果、クロスドメイン認証用の非常に優れたコンパクトなライブラリが得られました。これは、かなり長い期間にわたって証明されています。 同時に、現在発生しているように、サイトの第2レベルドメインが共通である場合、不要なリダイレクトは実行されず、すべての認証は透過的です。 FreeBSDで動作するサイトは、クライアントパーツ自体の実装を強制されますが、これはかなり簡単な作業です。 以下にコメントを示します。
- セッションの一般的なストレージは本格的なデータベースである必要はありません。標準のセッションストアと、少なくともすべてをメモリに保持する適切なインターフェイスのセットを持つ独自のWCFサービスを使用できます。 私たちの場合、ポータルサイトは前述のWebService APIを介して中央サービスとデータを交換し、データベースは既に存在するため、内部ストレージとして使用されます。また、余分なエンティティを作成し、それらをサポートする意味はありませんが、一般的に、ストレージは手のわずかな動きに置き換えられます。 ..
- 私たちの場合のように、すべてのポータルサイトが事前にわかっている場合は、次の最適化を適用できます(開発者の言語=を使用して、認証をレイジーではなく貪欲にします):ユーザーが来るたびに中央サーバーに認証をリダイレクトする代わりに新しいサイトでは、ユーザーが正しいログイン/パスワードのペアを入力した直後に、IFrameのすべてのポータルサイトを開くことができるため、一度にすべてのサイトにリダイレクトが発生します(実際、この場合、リダイレクトなしで、 リクエストトークンにavを入力し、データベースから必要な情報を取得します)。 しかし、一般的な場合、これは信頼性が低く、何か問題が発生した場合、ユーザーの1つまたは複数のサイトが表示されなくなりますが、残りはすべて問題なく、最小限のダメージでこの状況を解決する方法はあまり明確ではありません。
- このスキームは、検索エンジンにあまり適していないという点で悪いです。 これらの人はリダイレクトを嫌い、匿名のクローラーがクッキーをサポートしていると言ったとしても、クッキーを保存していなくても、本当に悲しいことがわかりました。 このため、ライブラリの次のバージョンはデフォルトでjavascriptスキームで動作する可能性が高く、そのようなスクリプトにより適しています。 ただし、この場合、javascriptを持たないユーザーが影響を受けます。
共通デザインの作成。
大きく、美しく、分散された異種ポータルを作成するときに発生する別の問題は、共通の設計要素とそれらを表示する機能です。 ポータルの各部分(個別のサイト)には独自の開発チームがあり、既に述べたように、これらのサイトは異なるサーバーにデプロイされ、サーバーは物理的に異なる場所に配置され、オペレーティングシステムも異なります。 同時に、全体的なスタイルを維持しようとする必要があります。必要に応じてスタイルを変更するのが簡単であり、この置換がすべてのチームの側で大きな労力を必要としないような方法でさえ、理想的には、彼らの参加なしで行うでしょう。 したがって、UIを担当するコントロールのライブラリを作成する必要があります。これは、プロジェクトの参加者全員が、過度の労力なしで使用できます。
標準ASP.NetコントロールとMVCテンプレート(別名部分ビュー)は、このタスクではあまり成功しません。第一に、異なるプロジェクトの異なるチーム間で共有するのが不便であり、第二に、FreeBSDの人にとってはまったく役に立ちません。 考えた後、次のパターンが並んでいた...
各共通コントロールの中核はxml / xslバンドルです。 このようなコントロールのローカライズされたxmlは、同じAPIを介して中央サーバーから取得されます。これにより、場合によっては、さまざまな種類のメニューのレンダリングなど、中央サーバーで使用可能なデータに基づいてこのxmlを動的に構築できます。 最終的なhtmlを取得するためのXslは、共有ライブラリに関連する特別なアセンブリのリソースにあり、同じアセンブリには、中央サーバーからxmlを抽出し、xslで処理し、結果を正しくキャッシュするためのコードがあります。 ほとんどの場合、補助サイトでコントロールを使用するには、適切なパラメーターを指定してメソッドを呼び出すだけで十分です。コントロールがレンダリングされます。まれに、レンダリングプロセスに割り込んで特定のタスクのために少し修正する必要がある場合もありますが、これも問題ではありません。
FreeBSDや他の代替システムのプロジェクトでは、この種の制御を使用することも非常に便利です。 もちろん、xml-thを取得し、対応するxsl-thおよびその他のボイラープレートスクワットを適用するロジックは、独立して実装する必要がありますが、共通要素を描画する際のほとんどの問題は解決されます。 すべての場合において、Xmlとxslは同じであり、必要に応じて、レンダリングロジックを一元的に変更したり、コントロールを塗りつぶしたりすることはそれほど負担ではありません。
オンラインストア。
話をするのに意味のあるポータルの生活のもう1つの側面は、オンラインストアです。 将来的には、各ポータルサイトには販売するものがあり、サイトだけでなく、少し拒否するためのオンラインサービスを提供したり、配布キットを販売したりすることが役立つ場合もあります。 各店舗を実現するために、店舗は非生産的なアイデアです。 もちろん、プラスはありますが、マイナスはまだあります。 しかし、集中型店舗の実施には障害もあります。主なことは、何を売らなければならないかが事前にわからないことであり、商品はサービスから箱まで非常に多様です。 また、すでに述べたように、将来的には、明らかにポータル構造の一部であるサイトだけでなく、雑貨店で製品を販売する必要があるかもしれません。
成功した解決策は、店舗の店頭と注文に対する実際の支払いプロセスを分離することでした。 明らかに、ショーケースを一般化することはあまり意味がありません-製品は最も多様であり、特にポータルの作成時に提案された製品の大部分が知られていないため、普遍的な便利なデザインを想像することはできません。 したがって、店舗の「ショーケース」、つまり、価格やその他の説明を含む商品のカタログにより、販売したい各サービスを個別に販売できます。 しかし、商品をバスケットに入れてさらにこのバスケットの支払いをするプロセスは、すべての人に共通するのが理にかなっています-ロジックはかなり曖昧ですが、普遍的であるため、一度実装することができ、たとえば、新しい支払い方法を接続するなど、すべての人に自動的に機能しますサービス。
サイトのユーザーが「バスケットに入れる」ボタンをクリックすると、サイトはここで言及したAPIの助けに何度も頼り、そのようなユーザー(覚えているように、クロスドメイン認証システムが完全に機能している)がバスケットはそのような製品であり、そのような価格であり、店舗の一般的な部分は、注文をさらに形成するためにこれらすべてのデータを記憶しています。
さらに、バスケットに行くと、ユーザーはすでに中央サイトにアクセスしており、そこで支払いプロセスおよび選択した支払いシステムとのその他のやり取りが行われます。 注文が正常に支払われた後、中央サイトは、バスケットに商品が入っていたすべてのサービスに、ユーザーがそのような商品やそのような商品の支払いを済ませたという通知を送信します。
当初、中央集権型店舗のアイデアを拒否しましたが、すべてのサービスの中で最も人気のある製品が提示される一般的なショーケースが依然として必要です。 これは、マーケティングと販売(クロスブランディングなど)の観点から、またデザインと使いやすさの観点から、非常に有用なものです。特定のセクションではなく、「ただの店」へのリンクが常に必要です。 そのため、共通のストアフロントで製品を表示したいすべてのサービスは、この同じストアフロントに関連情報を提供する簡単なRESTfulメソッドを実装する必要があります。
おわりに
結論として、ここでは、最も一般的な用語で、ポータルアーキテクチャの一部のみを説明しています。これは、ユーザーの利益のために、さまざまなオンラインサービスのアンサンブル全体を互いに平和に共存させることを強制する試みに関連しています。 :)それぞれのサービスは独自の方法でユニークで興味深いです... :)
イワン・ボディアギン
テキスト認識製品部