クライアント|クッキー|クッキー|マルチスレッド
— 著者 sunggsun @ 20:26
8. Cookies
HttpClient は、サーバーが Cookie を設定したり、必要に応じて自動的に Cookie をサーバーに返したりすることを含め、Cookie を自動的に管理できます。また、手動での Cookie の設定と送信もサポートしています。それらをサービスターミナルに送信します。残念ながら、Cookie の処理方法に関しては、いくつかの矛盾する仕様があります。Netscape Cookie Draft、RFC2109、RFC2965、および多くのソフトウェア ベンダーの Cookie 実装は、どの仕様にも準拠していません。この状況に対処するために、HttpClient はポリシー駆動型の Cookie 管理を提供します。 HttpClient でサポートされている Cookie 仕様は次のとおりです:
Netscape Cookie ドラフト。これは最も初期の Cookie 仕様であり、rfc2109 に基づいています。 rc2109とは仕様が大きく異なりますが、一部のサーバーでは互換性があります。
rfc2109 は、w3c によってリリースされた最初の公式 Cookie 仕様です。理論上、すべてのサーバーは Cookie (バージョン 1) を処理するときにこの仕様に従う必要があり、このため、HttpClient はこれをデフォルトの仕様として設定します。残念ながら、この仕様は非常に厳格であるため、多くのサーバーが仕様を誤って実装しているか、依然として Netscape 仕様を使用しています。この場合、互換仕様を使用する必要があります。
互換性仕様。標準仕様に従っていない場合でも、できるだけ多くのサーバーと互換性があるように設計されています。 Cookie の解析で問題が発生した場合は、互換性の仕様を考慮する必要があります。
RFC2965 仕様は現在 HttpClient でサポートされていません (将来のバージョンで追加されます) Cookie バージョン 2 を定義し、RFC2965 は長期的には rfc2109 を置き換えることを目的としています。 2 つの Cookie 仕様の使用を指定するメソッド、
HttpClient client = new HttpClient();
client.getState().setCookiePolicy(CookiePolicy.COMPATIBILITY);
このメソッドで設定された仕様は、現在の HttpState に対してのみ有効であり、パラメーターには、CookiePolicy .COMPATIBILITY、CookiePolicy.NETSCAPE_DRAFT、または CookiePolicy.RFC2109 の値を指定できます。
System.setProperty("apache.commons.httpclient.cookiespec", "COMPATIBILITY");
このメソッドによって参照される仕様は、今後新しく作成される各 HttpState オブジェクトに対して有効です。パラメーターは値 "COMPATIBILITY" を取ることができます。 、「NETSCAPE_DRAFT」、または「RFC2109」。
Cookieが解析できない問題はよくありますが、互換性のある仕様に変更することでほとんどが解決できます。
9. HttpClient の使用中に問題が発生した場合はどうすればよいですか?
ブラウザを使用してサーバーにアクセスし、サーバーの応答が正常であることを確認します
プロキシを使用している場合は、プロキシをオフにしてみてください
別のサーバーを見つけて試してください (別のサーバー ソフトウェアを実行している場合はより良いでしょう)
チュートリアルのアイデアに従ってコードが記述されているかどうかを確認してください
問題の原因を見つけるためにログ レベルをデバッグに設定してください
wiretrace を開き、クライアントとサーバー間の通信を追跡します。問題が発生している場所を正確に確認します。
telnet または netcat を使用して、原因を推測した後のテストに適しています。
netcat をリスニング モードで実行し、httpclient が応答をどのように処理するかを確認するサーバーとして使用します。
最新の httpclient を使用してみてください。バグは最新バージョンで修正されている可能性があります。
メーリング リストでヘルプを求めてください。
バグを bugzilla に報告してください。
10、SSL
Java Secure Socket Extension を使用します。 (JSSE)、HttpClient は、HTTP over Secure Sockets Layer (SSL) または IETF Transport Layer Security (TLS) プロトコルを完全にサポートします。 JSSE は jre1.4 以降のバージョンに含まれています。以前のバージョンでは手動でのインストールと設定が必要です。具体的なプロセスについては、Sun の Web サイトまたはこの調査ノートを参照してください。
HttpClient での SSL の使用は非常に簡単です。次の 2 つの例を参照してください。
HttpClient httpclient = new HttpClient();
GetMethod httpget = new GetMethod("https://www.verisign.com/");
httpclient.executeMethod (httpget );
System.out.println(httpget.getStatusLine().toString());
、承認が必要なプロキシ経由の場合は、次のようになります:
HttpClient httpclient = new HttpClient();
httpclient.getHostConfiguration ().setProxy( "myproxyhost", 8080);
httpclient.getState().setProxyCredentials("my-proxy-realm", " myproxyhost",
new UsernamePasswordCredentials("my-proxy-username", "my-proxy-パスワード"));
GetMethod httpget = new GetMethod("https://www.verisign.com/");
httpclient.executeMethod(httpget);
System.out.println(httpget.getStatusLine().toString() );
HttpClient で SSL をカスタマイズする手順は次のとおりです:
は、org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory インターフェイスを実装するソケット ファクトリを提供します。このソケット ファクトリは、サーバーへのポートを開き、標準またはサードパーティの SSL 関数ライブラリを使用し、接続ハンドシェイクなどの初期化操作を実行します。通常、この初期化操作はポートの作成時に自動的に実行されます。
org.apache.commons.httpclient.protocol.Protocol オブジェクトをインスタンス化します。このインスタンスを作成するときは、有効なプロトコル タイプ (https など)、カスタマイズされたソケット ファクトリ、およびデフォルトのポート番号 (https ポート 443 など) が必要です。
Protocol myhttps = new Protocol("https", new MySSLSocketFactory ())。 , 443);
このインスタンスは、プロトコルのハンドラーとして設定できます。
HttpClient httpclient = new HttpClient();
httpclient.getHostConfiguration().setHost("www.whatever.com", 443, myhttps);
GetMethod httpget = new GetMethod("/");
httpclient.executeMethod(httpget) ;
Protocol.registerProtocol メソッドを呼び出すことにより、このカスタマイズされたインスタンスを特定のプロトコルのデフォルト プロセッサとして登録します。これにより、独自のプロトコル タイプ (myhttps など) を簡単にカスタマイズできます。
Protocol.registerProtocol("myhttps",
new Protocol("https", new MySSLSocketFactory(), 9443));
...
HttpClient httpclient = new HttpClient();
GetMethod httpget = new GetMethod("myhttps:/ /www.whatever.com/");
httpclient.executeMethod(httpget);
https のデフォルトのプロセッサを独自にカスタマイズしたプロセッサに置き換える場合は、それを「https」として登録するだけです。
Protocol.registerProtocol("https",
new Protocol("https", new MySSLSocketFactory(), 443));
HttpClient httpclient = new HttpClient();
GetMethod httpget = new GetMethod("https://www.whatever .com/");
httpclient.executeMethod(httpget);
既知の制限事項と問題点
永続的な SSL 接続は、1.4 より前の Sun の JVM では機能しません。これは、JVM のバグが原因です。
プロキシ経由でサーバーにアクセスすると、非プリエンプティブ認証は失敗します。これは HttpClient の設計上の欠陥が原因であり、将来のバージョンで修正される予定です。
問題の対処方法
特に jvm が 1.4 未満の場合の多くの問題は、jsse のインストールが原因で発生します。
最終的な検出方法として次のコードを使用できます。
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.net.Socket;
import javax.net.ssl; SSLSocketFactory;
public class Test {
public static Final String TARGET_HTTPS_SERVER = "www.verisign.com";
public static void main(String[] args) throws Exception {
ソケットソケット = SSLSocketFactory.getDefault().
createSocket(TARGET_HTTPS_SERVER, TARGET_HTTPS_PORT);
try {
Writer out = new OutputStreamWriter(
socket.getOutputStream(), "ISO-8859-1");
out.write("GET / HTTP/1.1rn");
out.write("ホスト: " + TARGET_HTTPS_SERVER + ":" +
TARGET_HTTPS_PORT + "rn");
out.write("エージェント: SSL-TESTrn");
out.write ("rn");
Out.flush();
BufferedReader in = new BufferedReader(
new InputStreamReader(socket.getInputStream(), "ISO-8859-1"));
文字列行 = null;
while (( line = in.readLine()) != null) {
System.out.println(line);
}
} 最後に {
socket.close();
11. -threading
マルチスレッドを使用する主な目的は、並列ダウンロードを実現することです。 httpclient の実行中、各 http プロトコル メソッドは HttpConnection インスタンスを使用します。接続はリソースが限られており、各接続は一度に 1 つのスレッドとメソッドでのみ使用できるため、必要に応じて接続が正しく割り当てられるようにする必要があります。 HttpClient は、jdbc 接続プールと同様の方法を使用して接続を管理します。この管理作業は MultiThreadedHttpConnectionManager によって実行されます。
MultiThreadedHttpConnectionManager connectionManager =
new MultiThreadedHttpConnectionManager();
HttpClient client = new HttpClient(connectionManager); これは、クライアントを複数のスレッドで複数のメソッドを実行するために使用できることです。 HttpClient.executeMethod() メソッドが呼び出されるたびに、リンク マネージャーから接続インスタンスが適用され、アプリケーションが成功すると、リンク インスタンスがチェックアウトされ、リンクの使用後にマネージャーに返される必要があります。 。マネージャーは 2 つの設定をサポートしています: maxConnectionsPerHost ホストごとの並列接続の最大数、デフォルトは 2
maxTotalConnections クライアント上の合計並列接続の最大数、デフォルトは 20 です
マネージャーがリンクを再利用する場合、次の方法を採用します。最初に返されたものを再利用します (最も最近使用されていないアプローチ)。
HttpClient 自体ではなく、応答パケットの本文を読み取るために HttpClient プログラムが使用されるため、HttpClient は接続がいつ使用されなくなるかを判断できません。これには、応答の本文を読み取った後に releaseConnection(() を手動で明示的に呼び出す必要があります。パケット)を使用してアプリケーションリンクを解放します。
MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
HttpClient client = new HttpClient(connectionManager);
...
// 特定のスレッド内。
GetMethod get = new GetMethod("http://jakarta.apache.org/");
try {
client.executeMethod(get);
// stdout への応答を出力
System.out.println(get.getResponseBodyAsStream() );
} 最後に {
// 接続が解放されて接続
// manager
get.releaseConnection();
}
各 HttpClient.executeMethod に一致する method.releaseConnection() が存在する必要があります。
12. HTTP メソッド
HttpClient でサポートされている HTTP メソッドは 8 つあり、以下で説明します。
1. Options
HTTPメソッドのOptionsは、リクエストURL(リクエストURL)でマークされたリソースのリクエスト/レスポンス通信プロセスで使用できる機能オプションを取得することを期待して、サーバーにリクエストを送信するために使用されます。 。この方法により、クライアントは、特定のアクションを実行する前に、実行するアクションやリソースに必要な条件を決定したり、サーバーが提供する機能を理解したりできます。このメソッドの最も一般的な用途は、サーバーがサポートしている HTTP メソッドを取得することです。
このHTTPメソッドをサポートするためのHttpClientにはOptionsMethodというクラスがあり、このクラスのgetAllowedMethodsメソッドを利用することで上記の代表的なアプリケーションを簡単に実装することができます。
OptionsMethod options = new OptionsMethod("http://jakarta.apache.org");
// メソッドを実行し、対応する例外を処理します
...
Enumeration allowedMethods = options.getAllowedMethods();
options。 releaseConnection();
2. Get
HTTPメソッドのGETは、リクエストURI(request-URI)でマークされたあらゆる情報を(エンティティの形式で)取得するために使用されます。「get」という言葉の本来の意味は「」です。 「得る」という意味です。リクエスト URI がデータ処理プロセスを指している場合、このプロセスによって生成されたデータは、このプロセスのコードではなく、エンティティの形式で応答に返されます。
HTTP パケットに If-ModifiedSince、If-Unmodified-Since、If-Match、If-None-Match、If-Range などのヘッダー フィールドが含まれている場合、GET は「条件付き GET」になります。つまり、次の場合に限ります。上記の条件が満たされている フィールドに記述されている条件に従ってエンティティが取得されます。これにより、不必要なネットワーク送信が削減され、特定のリソースを取得するための複数のリクエスト (最初のチェック、2 回目のダウンロードなど) が削減されます。 (一般的なブラウザには、Web ページの一部の情報をキャッシュするために使用される一時ディレクトリがあります。ページを再度閲覧するときに、閲覧を高速化するために、変更された内容のみがダウンロードされます。これが理由です。確認に関しては、GET よりも優れた方法が一般的に使用されます) HTTP パケットに Range ヘッダー フィールドが含まれる場合、リクエスト URI で指定されたエンティティのうち、範囲条件を決定する部分のみが取得されます。 (マルチスレッドのダウンロード ツールを使用している友人は、これをより簡単に理解できるかもしれません)
このメソッドの一般的なアプリケーションは、Web サーバーからドキュメントをダウンロードするために使用されます。 HttpClient は、このメソッドをサポートする GetMethod というクラスを定義します。GetMethod クラスの getResponseBody、getResponseBodyAsStream、または getResponseBodyAsString 関数を使用して、応答パッケージ本体内のドキュメント (HTML ページなど) 情報を取得できます。これら 3 つの関数のうち、通常は getResponseBodyAsStream が最適なメソッドです。これは主に、ダウンロードされたドキュメントを処理する前にダウンロードされたすべてのデータをキャッシュする必要がないためです。
GetMethod get = new GetMethod("http://jakarta.apache.org");
// メソッドを実行し、失敗したリクエストを処理します。
...
InputStream in = get.getResponseBodyAsStream();
//入力ストリームを使用して情報を処理します。
get.releaseConnection();
GetMethod の最も一般的な誤った使用法は、応答本体のデータをすべて読み込まないことです。また、リンクを手動で明示的に解放するように注意する必要があります。
3. Head
HTTPのHeadメソッドはGetメソッドとまったく同じですが、唯一の違いは、サーバーが応答パケットにボディ(message-body)を含めることができないことと、ボディを含めてはいけないことです。この方法を使用すると、顧客はリソースをダウンロードし直すことなく、リソースに関する基本情報を取得できます。このメソッドは、ハイパーリンクのアクセシビリティと、リソースが最近変更されたかどうかを確認するためによく使用されます。
HTTP の head メソッドの最も典型的な用途は、リソースに関する基本情報を取得することです。 HttpClient は、このメソッドをサポートする HeadMethod クラスを定義します。HeadMethod クラスは、他の *Method クラスと同様に、独自の特別なメソッドを持たずに getResponseHeaders() を使用してヘッダー情報を取得します。
HeadMethod head = new HeadMethod("http://jakarta.apache.org");
// メソッドを実行し、失敗したリクエストを処理します。
...
// 応答パケットのヘッダフィールド情報を取得します。
Header[] headers = head.getResponseHeaders();
// 最終更新日フィールドの情報のみを取得します
String lastModified = head.getResponseHeader("last-modified").getValue();
4. Post
Post は英語で「ステーション」を意味します。HTTP メソッド POST では、サーバーがリクエスト パッケージ内のエンティティを受け入れ、それをリクエスト URI の下位リソースとして使用する必要があります。これは基本的に、サーバーがこのエンティティ情報を保存し、通常はサーバー側プログラムによって処理されることを意味します。 Post メソッドの設計意図は、次の機能を統一された方法で実現することです:
既存のリソースにコメントを作成します
BBS、ニュース グループ、メーリング リスト、または類似の記事グループに情報を公開します
データ処理プロセスにデータを送信します
追加操作を通じてデータベースを拡張します
これらすべての操作で生成されることが期待されていますデータベースの変更など、サーバー側での特定の「副作用」。
HttpClient は、この HTTP メソッドをサポートする PostMethod クラスを定義します。 httpclient では、post メソッドを使用するための 2 つの基本的な手順があります。1 つはリクエスト パケットのデータを準備し、次にサーバーから応答パケットの情報を読み取ることです。 setRequestBody() 関数を呼び出して、リクエスト パッケージにデータを提供します。この関数は、入力ストリーム、名前と値のペアの配列、または文字列の 3 種類のパラメーターを受け取ることができます。応答パケットを読み取るためにgetResponseBody*を呼び出す必要がある一連のメソッドは、応答パケットを処理するGETメソッドと同様です。
よくある問題は、応答全体が(プログラムにとって有用かどうかに関係なく)読み取られないこと、またはリンク リソースが解放されないことです。