-
Notifications
You must be signed in to change notification settings - Fork 0
MS_HttpClientUsage
-
TOP > インフラストラクチャ > 通信技術 > WebAPI
- HttpClientの類の使い方
- Exponential Backoff(指数バックオフ)
- Polly
.NETクライアントからHTTPリクエストを送る場合、従来は、
使用していたが、こちらは設計が古いもよう。
新しくは、.NET Framework 4.5 では BCL 入りした
System.Net.Http.dll の HttpClientクラスを使用する。
- HttpClientクラスのFactoryクラス
- .NET Core 2.1 以降で使用できる。
HttpClientクラスのハンドラ委任を構成可能。
- ネーミングや構成を管理
- HttpClientクラスのライフサイクルを管理
- クリーン・アーキテクチャっぽく Polly を統合
- 設定(DI Container に登録)
- 使う場所で呼び出す
- 基本的には、Controllerに DI(constructor注入)し、
使う場所で、CreateClient(Factoryメソッド)を呼び出す。 - Named Clients では、名前を指定して、CreateClient(Factoryメソッド)を呼び出す。
- TypedClients では、
- 指定の型に DI する。
- 型には、以下がある。
- クラス(constructor注入)
- インターフェイス(Refit の live interface)
- ASP.NET Core で IHttpClientFactory を使用して HTTP 要求を行う
- Polly — 回復力の高いアプリケーションの実装
- HttpClient よりも HttpClientFactory を利用したほうが良いかも - 世界のやまさ
.NET Framework 4.5 で BCL 入りした、高機能で使い勝手がいいAPI。
// HttpClient
private static HttpClient _httpClient = new HttpClient();
// 通信用の変数
HttpRequestMessage httpRequestMessage = null;
HttpResponseMessage httpResponseMessage = null;
// HttpRequestMessage (Method & RequestUri)
httpRequestMessage = new HttpRequestMessage
{
Method = HttpMethod.Get,
RequestUri = new Uri("http://localhost/・・・"),
};
// HttpRequestMessage (Headers & Content)
httpRequestMessage.Headers.Authorization = new AuthenticationHeaderValue(
"Basic",
Convert.ToBase64String(System.Text.Encoding.ASCII.GetBytes(
string.Format("{0}:{1}", "・・・", "・・・"))));
httpRequestMessage.Headers.ExpectContinue = false;
// HttpResponseMessage
httpResponseMessage = await _httpClient.SendAsync(httpRequestMessage);
response = await httpResponseMessage.Content.ReadAsStringAsync();
return (JObject)JsonConvert.DeserializeObject(response);移行メモ: 原文のサンプルは
RequestUri = new Uri("http://localhost/・・・",と 閉じ括弧が欠けていた(コンパイルできない)。閉じ括弧を補った。
POST については、上記GETのコードの
-
Method = HttpMethod.Get→Method = HttpMethod.Postに変更。 -
httpRequestMessage.Contentプロパティを設定する。
// HttpRequestMessage (Method & RequestUri)
httpRequestMessage = new HttpRequestMessage
{
Method = HttpMethod.Post,
RequestUri = new Uri("http://localhost/・・・"),
};
// HttpRequestMessage (Headers & Content)
httpRequestMessage.Headers.Authorization = new AuthenticationHeaderValue(
"Basic",
Convert.ToBase64String(System.Text.Encoding.ASCII.GetBytes(
string.Format("{0}:{1}", "・・・", "・・・"))));
httpRequestMessage.Content = new FormUrlEncodedContent(
new Dictionary<string, string>
{
{ "grant_type", "authorization_code" },
{ "code", code },
{ "redirect_uri", "http://localhost/・・・" },
});
// HttpResponseMessage
httpResponseMessage = await _httpClient.SendAsync(httpRequestMessage);
response = await httpResponseMessage.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<Dictionary<string, string>>(response);移行メモ(正誤): 原文は
redirect_uriの値をSystem.Web.HttpUtility.HtmlEncode(...)で包んでいたが、 HtmlEncode は HTML 用のエスケープで、フォーム送信値には不要かつ有害 (&が&になるなど値が変わる)。FormUrlEncodedContentが URL エンコードを行うため、生の値を渡せばよい。 URL エンコードを明示したい場合はUri.EscapeDataStringを使う。
JSONのPOSTについては、
上記コードの httpRequestMessage.Content プロパティにJSON文字列を指定する。
httpRequestMessage.Content = new StringContent(
JsonConvert.SerializeObject(new
{
language = "ja"
}),
Encoding.UTF8, "application/json");※ 現在の .NET では System.Net.Http.Json の拡張メソッド
(PostAsJsonAsync / ReadFromJsonAsync)を使えば、
System.Text.Json ベースで同等の処理を簡潔に書ける。
- 以下の問題があるので、HttpClientは基本的に、
- static で使用する。
- 都度、instance化しないこと(適切にdisposeしてもダメ)。
- これは、都度、instanceすると、ソケットを爆発させるため(TIME_WAIT の枯渇)。
補足: static 化にも副作用があり、 DNS の変更が反映されない(ソケットを掴んだままになる)という逆の問題が起きる。 このため現在は、
IHttpClientFactoryを使う(ハンドラを一定時間でローテートする)か、SocketsHttpHandler.PooledConnectionLifetimeを設定するのが推奨。「static にする」は問題の半分だけの解になっている点に注意。
- 参考
以下が参考になる。
認証プロキシを通す場合と同じだが、
-
- 「WebBrowser」はlocalhostでも表示されるが、
- 「Non-Browser」(≒ HttpClient)はlocalhostが表示されない。
という(非常に痛い)問題がある。
(WebProxy.BypassProxyOnLocal辺りの問題と切り分けが困難) -
以下の「http://localhost」をhostsファイルで別名に変更すると、\ 「Non-Browser」でも、ログに表示されるようになる。
using System;
using System.Net.Http;
namespace ConsoleApp1
{
class Program
{
//private static readonly string proxyUrl = "http://127.0.0.1:8888";
//private static readonly string proxyAccount = "account";
//private static readonly string proxyPassword = "password";
private static readonly string targetUrl = "http://localhost/iisstart.htm";
static void Main(string[] args)
{
// HttpClientHandlerにProxy情報を設定する
HttpClientHandler ch = new HttpClientHandler();
//ch.Proxy = new WebProxy(proxyUrl);
//ch.Proxy.Credentials = new NetworkCredential(proxyAccount, proxyPassword);
//ch.UseProxy = true;
// HttpClientHandlerを用いてHttpClientを生成
HttpClient client = new HttpClient(ch);
try
{
// GETでレスポンスを取得
var task = client.GetStringAsync(targetUrl);
task.Wait();
Console.WriteLine(task.Result);
}
catch (Exception e)
{
Exception e2 = e.GetBaseException();
System.Console.WriteLine(e2.Message);
}
Console.ReadKey();
}
}
}handlerに以下を加える。
handler.ServerCertificateCustomValidationCallback =
(message, cert, chain, errors) => { return true; };補足: この設定は中間者攻撃を素通しにするため、 開発・デバッグ環境限定。本番コードに残さないこと。
HttpClientには、ハンドラ委任と言う概念がある。
- HttpClientの実行前後のパイプラインに、
DelegatingHandlerを追加できる。 - ハンドラの構成には、HttpClientFactoryクラスが使用される。
- 参考
- HttpClient クラス (System.Net.Http)
- .NET TIPS:HttpClientクラスでWebページを取得するには? - @IT
- HttpClient詳解、或いは非同期の落とし穴について
- .NETでHTTPリクエストを処理するための最古のAPI。
- 内部では、WebRequest, WebResponseクラスが利用される。
- 参考
Silverlight が SOAP サーバーと通信するケースが増えたため、追加されたAPI。
- WebClientとの違いは、
- WebRequest, WebResponseの2クラスに分割され、非同期対応がなされた。
- WebRequest を使用して Request を送信し、Callback で WebResponse を取得する。
- 各クラスには以下の派生クラスがある。
- HttpWebRequest、FileWebRequest、FtpWebRequest
- HttpWebResponse、FileWebResponse、FtpWebResponse
- .NET Core の HttpWebRequest については、
内部的にHttpClientクラスを new してアクセスしているらしい。
移行メモ(正誤): 原文は「WebResponseを使用してRequestを送信し、 CallbackでWebResponseを取得する」となっていたが、 Request を送信するのは WebRequest。
補足(最新化):
WebClient/WebRequest/HttpWebRequestはいずれも Obsolete 属性が付与された非推奨 API(.NET 6 以降)。 新規実装ではHttpClientを使う。
Tags: プログラミング, 通信技術, .NET開発, .NET Core, ASP.NET, ASP.NET Web API
このWikiは「Open棟梁Project」,「OSSコンソーシアム 開発基盤部会」によって運営されています。