Java Application EngineアプリでのPubSubHubbubサブスクリプションの実装

PubSubHubbub タイトルに示されているトピックを扱うと、RuNetでの公開はかなり不十分でしたが、このプロトコルの提出から多くの時間が経過しました。 私の経験を共有して、この小さなギャップをわずかに埋めたいと思います。

PubSubHubbubPuSH )はGoogleによって提案されたプロトコルであり、パブリッシャーからサブスクライバーへのRSSフィードを介したデータ配信プロセスを効率化するように設計されていることを簡単に思い出させてください。 プロトコルの動作を保証するスキームの中心は、直接データソースとその最終受信者の間の仲介者として機能する独立したハブに割り当てられます 。 同時に、ハブは、登録されたチャネルのすべてのサブスクライバーに、データの新しい部分を送信しながら、出現後すぐに新しいデータを受信したことを通知します。

したがって、RSSまたはAtom形式のフィードを処理するアプリケーションを作成している場合、「黒」作業をハブに割り当てることで、作業を大幅に楽にすることができます。 そのようなスキームの特定の利点:



つまり、迅速なデータ配信が可能になり、着信トラフィックの量とアプリケーションのプロセッサ時間の両方を大幅に節約できます。 クォータによって制限されるApp Engineアプリケーションの場合、これらのポイントが重要になる場合があります。 さらに、より少ない量の単純なコードを記述する必要があるため、時間を節約できます。

以下は、ハブの1つで正常にテストしたJavaコードの最小限必要なフラグメントです。 コードは非常に小さくシンプルです。





したがって、これはハブからデータを受信するサブスクライバーアプリケーションです。 プロトコルに従って、ハブと対話する加入者のシナリオには以下が含まれます。

  1. サブスクリプション要求は、チャネルアドレスとサブスクライバーアドレスと共にハブに送信されます。
  2. ハブはチャネルをチェックし、サブスクリプションの確認を求めるリクエストをサブスクライバーに送信します。
  3. サブスクライバーはサブスクリプションを確認します。
  4. ハブはサブスクライバーに通知し、チャンネルに表示される新しいデータを彼に配信します。
  5. 一定時間後、ハブはサブスクライバーにサブスクリプションの確認を再要求します。


このシナリオは、最小限のアプリケーションが以下を実行できるサーブレットを実装する必要があることを意味します。

  1. ハブリクエストへの応答でサブスクリプションを確認します。
  2. 新しいデータの一部を含む次の区画を受け入れます。


さらに、サブスクリプションを要求するための実際の手順を実装する機能を備えている場合があります。



サブスクリプションリクエスト



私が試したハブでは、サービスの適切なWebインターフェイスを使用して「手動」でサブスクリプションを要求できるため、この手順はアプリケーション内では必要ありません。

サブスクリプションを要求する場合、4つの必須パラメーターの値をハブに通知する必要があります。

  1. サブスクライバーURL( hub.callback ):ハブが対話するアプリケーションサーブレットのアドレス。
  2. リクエストのタイプ( hub.mode ):希望するアクション、すなわちサブスクリプション、または拒否(サブスクライブ/サブスクライブ解除)。
  3. 購読済みチャンネルURL( hub.topic ):メッセージを受信したいチャンネルのアドレス。
  4. 要求確認方法( hub.verify ):サブスクリプション確認(同期/非同期)の即時(同期)要求の必要性またはオプションについてハブに通知します。


さらに、ハブは次のようなオプションのパラメーターをサポートする場合があります。



「手動」サブスクリプションモードに満足したら、次のセクションに進むことができます。

ただし、アプリケーションが独自にサブスクライブする必要がある場合があります。 この手順を実装する関数の例を次に示します。



import java.net.URL;

import java.net.URLEncoder;

import java.net.HttpURLConnection;

import java.io.OutputStreamWriter;

import com.google.appengine.repackaged.com.google.common.util.Base64;



// ..



public static void pshbSubscribe( ストリングコールバック、 ストリングモード、 ストリングトピック、 ストリングベリファイ)throws IOException {



コールバック= URLEncoder.encode( "hub.callback""UTF-8" )+ "=" + URLEncoder.encode(callback、 "UTF-8" );

mode = URLEncoder.encode( "hub.mode""UTF-8" )+ "=" + URLEncoder.encode(mode、 "UTF-8" );

topic = URLEncoder.encode( "hub.topic""UTF-8" )+ "=" + URLEncoder.encode(topic、 "UTF-8" );

verify = URLEncoder.encode( "hub.verify""UTF-8" )+ "=" + URLEncoder.encode(verify、 "UTF-8" );

文字列本体=コールバック+ "&" +モード+ "&" +トピック+ "&" +検証;



URL url = 新しい URL( " myhub.com/hubbub " );

HttpURLConnection connection =(HttpURLConnection)url.openConnection();

connection.setDoOutput( true );

connection.setRequestMethod( "POST" );

connection.setRequestProperty( "Content-Type""application / x-www-form-urlencoded" );



connection.setRequestProperty( "Authorization"

“ Basic„ + Base64.encode(( “ myname:mypwd” ).getBytes()));



OutputStreamWriter writer = new OutputStreamWriter(connection.getOutputStream());

writer.write(body);

writer.close();



if (connection.getResponseCode()!= HttpURLConnection.HTTP_NO_CONTENT){

//エラー

// ..

}

}



*このソースコードは、 ソースコードハイライターで強調表示されました。


プロトコルによると、サブスクリプション要求は、フォーム値の転送に使用される標準形式でハブ( " myhub.com/hubbub ")によって提供されるアドレスへのPOST要求です(「 Content-Type 」はapplication / x-www -form-urlencoded ")。 メッセージの本文は、上記の音声パラメータを送信します。

コードをテストしたハブには、事前登録と、認証付きサブスクリプション(HTTP基本認証)の要求が必要です。 ここから、ハブユーザーのユーザー名とパスワード(「 myname:mypwd 」)を使用した「承認」が行われます。 私が理解しているように、これは特定のハブの機能です。

サブスクリプションが成功した場合、ハブは204(「コンテンツなし」)、または非同期検証の場合は202(「Accepted」)を返す必要があります(hub.verifyが「async」に設定された場合)

したがって、サブスクリプションリクエストの例は次のようになります。



pshbSubscribe( " myapp.appspot.com/subscribe ""subscribe"" habrahabr.ru/rss/blogs/java ""sync" );



最初のパラメーターは、アプリケーションサーブレットのアドレスです。 次に、このサーブレットの操作を検討します。



サブスクリプションの確認



サブスクリプション要求を受信した後、ハブは受信したアドレスにGET要求を送信して確認を要求する必要があります。 この例では、これは「 myapp.appspot.com/subscribe 」です。 このアドレスで、アプリケーションはこのリクエストに応答するサーブレットを実装する必要があります。



import javax.servlet.http。*;

// ..



@SuppressWarnings( "serial"

パブリック クラス SubscribeServletはHttpServletを拡張します{

// ..



public void doGet(HttpServletRequest req、HttpServletResponse resp)

IOExceptionをスローします{



resp.setContentType( "text / plain" );

resp.setStatus(200);



if (req.getParameter( "hub.mode" )!= null

{

resp.getOutputStream()。print(req.getParameter( "hub.challenge" ));

resp.getOutputStream()。flush();

}

}

// ..



*このソースコードは、 ソースコードハイライターで強調表示されました。


リクエストでは、ハブはいくつかのパラメーターを渡します。これらの意味は、サブスクリプションのリクエストの場合と同じです。



パラメーター値が満足のいくものである場合(要求に対応する場合)、サブスクリプションを確認(または拒否)するには、応答で2xxコードを返し、応答本文に別のパラメーターの値を入力する必要があります: hub.challenge

リクエストを確認したくない場合は、404(「見つかりません」)を返します。

ハブが他のコード(3xx、4xx、5xx)を返す場合、問題があると判断され、検証は失敗します。

応答本文の内容がhub.challengeの値と異なる場合、ハブは検証が失敗したと見なします。

非同期要求メソッドが使用されている場合、障害(戻り3xx、4xx、5xx、または応答の内容がhub.challengeパラメーターと一致しない)の場合、ハブは確認を再度要求する必要があります。



ハブからデータを受信する



ハブは、サブスクライバーの新しいデータがあることを検出すると、サブスクライバーによって提供された既知のアドレスに対してPOST要求を実行します。 リクエスト本文では、このデータをRSSまたはAtom形式で送信します(「 Content-Type 」は「 application / rss + xml 」または「 application / atom + xml 」になります)。 リクエストを処理するために、サーブレットには次の機能があります。



public void doPost(HttpServletRequest req、HttpServletResponse resp)

IOExceptionをスローします{



SyndFeedInput input = new SyndFeedInput();

SyndFeed feed = input.build( new XmlReader(req.getInputStream()));



@SuppressWarnings( "未チェック"

リスト <SyndEntry> entriesList = feed.getEntries();



for (SyndEntryエントリ:entriesList)

{

文字列のタイトル= entry.getTitle();

文字列 author = entry.getAuthor();

URL url = 新しい URL(entry.getLink());



@SuppressWarnings( "未チェック"

リスト <SyndContent> contentsList = entry.getContents();

// ..



}

// ..



resp.setStatus(204);

}



*このソースコードは、 ソースコードハイライターで強調表示されました。


この例では、データを解析するためにフィード(SyndFeedInput、SyndFeed、SyndEntry、...)を操作するためのRomeライブラリのクラスを使用します。 特定の問題(ハブからXMPP経由で受信したデータの送信)を解決するために使用される同様のコードの例は、 ここにあります

サブスクリプション中にhub.secretパラメーターが定義された場合、リクエストには「 X1 -Hub -Signature 」パラメーターがあり、「 sha1 = signature 」という形式の値を持ちます。ここで、「signature」はリクエスト本文のコンテンツ(SHA1署名) メッセージの信頼性を検証するには、アプリケーション自体が、既知のhub.secretを使用してリクエスト本文のHMACコードを計算する必要があります。 結果が「署名」と一致する場合、メッセージは本物です。 詳細はこちら

メッセージが正常に受信された場合、X-Hub-Signatureチェックの結果に関係なく、2xxコードを返す必要があります。 特に返されない限り、ハブは成功コードを受信するまで、妥当な時間内にリクエストを再実行する必要があります。



参照:





All Articles