「[[マイクロソフト系技術情報 Wiki>http://techinfoofmicrosofttech.osscons.jp/]]」は、「[[Open棟梁Project>https://github.com/OpenTouryoProject/]]」,「[[OSSコンソーシアム .NET開発基盤部会>https://www.osscons.jp/dotNetDevelopmentInfrastructure/]]」によって運営されています。

-[[戻る>ASP.NET]]
-[[戻る>WebAPI]]

* 目次 [#sf757713]
#contents

*概要 [#e1a30627]
.NETクライアントからHTTPリクエストを送る場合、

従来は、
-[[WebClientクラス>#c6b27e18]]や
-[[WebRequest, WebResponseクラス>#t3ae0017]]を

使用していたが、こちらは設計が古いもよう。

新しくは、.NET Framework 4.5 では BCL 入りした~
System.Net.Http.dllの[[HttpClientクラス>#n074732e]]を使用する。

なお、JavaScriptからは、[[jQuery.ajax()>#m5888cea]]を使用する。
*HttpClientFactoryクラス [#o8484df8]

**概要 [#x1009ff5]
-[[HttpClientクラス>#n074732e]]のFactoryクラス
-.NET Core 2.1 以降で使用できる。

***特徴 [#l71c2c5d]
[[HttpClientクラス>#n074732e]]の[[ハンドラ委任>#b3ba802e]]を構成可能。

-ネーミングや構成を管理
-[[HttpClientクラス>#n074732e]]のライフサイクルを管理
-[[クリーン・アーキテクチャ>https://dotnetdevelopmentinfrastructure.osscons.jp/index.php?%E3%82%AF%E3%83%AA%E3%83%BC%E3%83%B3%E3%83%BB%E3%82%A2%E3%83%BC%E3%82%AD%E3%83%86%E3%82%AF%E3%83%81%E3%83%A3]]っぽく[[Polly>#n00a0b49]]を統合

**使い方 [#tc023e91]

***基本的な使い方 [#q35be5a1]
-設定([[DI]] Container に登録)
-使う場所で呼び出す

***使い方のパターン [#n85b9971]
-基本的には、~
Controllerに[[DI]](constructor注入)し、~
使う場所で、CreateClient(Factoryメソッド)を呼び出す。

-Named Clientsでは、~
名前を指定して、CreateClient(Factoryメソッド)を呼び出す。

-TypedClientsでは、
--指定の型に[[DI]]する。
--型には、以下がある。
---クラス(constructor注入)
---インターフェイス(Refitのlive interface)

***サンプル [#id72d551]
下記の[[参考>#vf058f30]]ページを見て。

**参考 [#vf058f30]

***Microsoft Docs [#z9f204bb]
-ASP.NET Core で IHttpClientFactory を使用して HTTP 要求を行う~
https://docs.microsoft.com/ja-jp/aspnet/core/fundamentals/http-requests

-[[Polly>#n00a0b49]]~
回復力の高いアプリケーションの実装
--カスタム HTTP 呼び出しの指数バックオフを含む再試行について~
https://docs.microsoft.com/ja-jp/dotnet/architecture/microservices/implement-resilient-applications/explore-custom-http-call-retries-exponential-backoff
--HttpClientFactory を使用して回復力の高い HTTP 要求を実装する~
https://docs.microsoft.com/ja-jp/dotnet/architecture/microservices/implement-resilient-applications/use-httpclientfactory-to-implement-resilient-http-requests

***その他 [#de3a6925]
-HttpClientFactory の使い方(ASP.NET Core 2.1-preview1) - BEACHSIDE BLOG~
https://blog.beachside.dev/entry/2018/05/15/190000

-HttpClient よりも HttpClientFactory を利用したほうが良いかも - 世界のやまさ~
https://blog.nnasaki.com/entry/2019/10/04/143936

-ASP.NET Core 2.1にて追加されたHttpClientFactory(とその周辺)を試す - 時が癒す~
http://mrgchr.hatenablog.com/entry/2018/03/09/000000

*HttpClientクラス [#n074732e]
.NET Framework 4.5 で BCL 入りした、高機能で使い勝手がいいAPI。

**サンプル [#u8db561a]

***GET [#hff0cdc1]

 // 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);

***POST [#vaee7008]
以下のHttpClientによるPOSTのサンプル・スニペットを使用すれば色々なパターンを処理可能。
POST については、[[上記GETのコード>#hff0cdc1]]の
-Method = HttpMethod.Get ---> Method = HttpMethod.Post に変更。
-httpRequestMessage.Content プロパティを設定する。

 // HttpClient
 private static HttpClient _httpClient = new HttpClient();

 // 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", System.Web.HttpUtility.HtmlEncode(
             "http://localhost/・・・") },
     });
 
 // HttpResponseMessage
 httpResponseMessage = await _httpClient.SendAsync(httpRequestMessage);
 
 response = await httpResponseMessage.Content.ReadAsStringAsync();
 dic = JsonConvert.DeserializeObject<Dictionary<string, string>>(response);
 return JsonConvert.DeserializeObject<Dictionary<string, string>>(response);

***GET [#hff0cdc1]
GETについては、[[上記コード>#vaee7008]]の
-Method = HttpMethod.Post ---> Method = HttpMethod.Get に変更。
-httpRequestMessage.Content プロパティを設定しない。

でイケる。と思う。

***JSON [#j80b5c5e]
JSONのPOSTについては、

>[[上記コード>#vaee7008]]のhttpRequestMessage.Content プロパティに[[JSON文字列を指定する>JSONのparseを色々試してみた。]]。

でイケる。と思う。

ちょっとコツがあった(以下のような感じ)。

 httpRequestMessage.Content = new StringContent(
   JsonConvert.SerializeObject(new
   {
     language = "ja"
   }),
   Encoding.UTF8, "application/json");


**ポイント [#l0c18008]

***Make your HttpClient static. [#vf2acf0c]
-以下の問題があるので、HttpClientは基本的に、
--staticで使用する。
--都度、instance化しないこと(適切にdisposeしてもダメ)。
--これは、都度、instanceすると、ソケットを爆発させるため。

-参考
--開発者を苦しめる.NETのHttpClientのバグと紛らわしいドキュメント~

--infoq.com

---開発者を苦しめる.NETのHttpClient~
のバグと紛らわしいドキュメント~
https://www.infoq.com/jp/news/2016/09/HttpClient
---You're using HttpClient wrong and it is destabilizing your software | ASP.NET Monsters~
https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/

---.NETのHttpClientの修正~
https://www.infoq.com/jp/news/2018/03/HttpClientFactory/

--Qiita

---.NETのHttpClientの取り扱いには要注意という話~
https://qiita.com/nskhara/items/b7c31d60531ffbe29537

---HttpClientをマルチスレッドで運用する場合の注意点~
https://qiita.com/skitoy4321/items/dc6bd2b62b62c2414642

-[[HttpClient × HttpClientFactory × より良い実装方法を調べてみた - きなこもち.net>https://www.kinakomotitti.net/entry/2021/04/03/164718#DIHttpClientFactory%E3%82%92%E3%81%A4%E3%81%8B%E3%81%A3%E3%81%9F%E4%BE%8B]]

***認証プロキシを通す場合 [#o5d5fc6b]
以下が参考になる。

-HttpClient で 認証プロキシ サーバーを使用するには – 荒井省三のBlog~
https://blogs.msdn.microsoft.com/shozoa/2014/09/02/httpclient/

***デバッグ・プロシキを通す。 [#o2f9ed91]
[[認証プロキシを通す場合>#o5d5fc6b]]と同じだが、

-[[Fiddler>電文を確認する方法(パケット・キャプチャ)#w11d3ad2]]は
--「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();
         }
     }
 }

***証明書の検証を無効化する。 [#m56ca19e]
handlerに以下を加える。
 handler.ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => { return true; };

-参考
--.NET CoreのHttpClientで無効な証明書を無視する - Azureの小ネタ (改)~
https://statemachine.hatenablog.com/entry/2018/03/10/122306

***その他のオプション [#i42fae72]
...

-参考
--C# HttpClientでタイムアウトを設定する - け日記~
https://ohke.hateblo.jp/entry/2017/05/12/202832
--HttpClient で HTTP 圧縮を使う - kazuakix の日記~
https://blog.kazuakix.jp/entry/2014/09/12/000636

***ハンドラ委任について。 [#b3ba802e]
HttpClientには、ハンドラ委任と言う概念がある

-HttpClientの実行前後のパイプラインに、~
HttpClientMessageHandlersを追加できる。

-ハンドラの構成には、[[HttpClientFactoryクラス>#o8484df8]]が使用される。

-参考
--ASP.NET Web API - ASP.NET の HttpClient メッセージ ハンドラー 4.x | Microsoft Docs~
https://docs.microsoft.com/ja-jp/aspnet/web-api/overview/advanced/httpclient-message-handlers

**参考 [#a1eb1525]

-HttpClient クラス (System.Net.Http)~
https://msdn.microsoft.com/ja-jp/library/system.net.http.httpclient.aspx

-.NET TIPS:HttpClientクラスでWebページを取得するには?[C#、VB] - @IT~
http://www.atmarkit.co.jp/ait/articles/1501/06/news086.html

-Web API よりも HttpClient に注目したい - しばやん雑記~
http://blog.shibayan.jp/entry/20120822/1345563275

-ASP.NET Web API シンプルな文字列の POST について - miso_soup3 Blog~
http://miso-soup3.hateblo.jp/entry/2014/06/02/000603

*WebClientクラス [#c6b27e18]
.NETでHTTPリクエストを処理するための最古のAPI。
-HttpClient詳解、或いは非同期の落とし穴について~
http://www.slideshare.net/neuecc/httpclient

**サンプル [#l4163c6f]
*旧式のクラス [#bdaef9a5]

**WebClientクラス [#c6b27e18]
-.NETでHTTPリクエストを処理するための最古のAPI。
-内部では、[[WebRequest, WebResponseクラス>#t3ae0017]]が利用される。

***サンプル [#l4163c6f]
以下が参考になる。

-DOBON.NET > .NET Tips: C#, VB.NET
--WebClientクラスでWebページを取得するには? - @IT~
http://www.atmarkit.co.jp/ait/articles/0505/20/news138.html
--ファイルをダウンロードし保存する~
http://dobon.net/vb/dotnet/internet/downloadfile.html
--ファイルをダウンロードし表示する~
http://dobon.net/vb/dotnet/internet/webclientopenread.html

**参考 [#hd232f9a]
***参考 [#hd232f9a]
-WebClient クラス (System.Net)~
https://msdn.microsoft.com/ja-jp/library/system.net.webclient.aspx

*WebRequest, WebResponseクラス [#t3ae0017]
SilverlightがSOAPサーバーと通信するケースが増えたため、追加されたAPI。
**WebRequest, WebResponseクラス [#t3ae0017]
[[Silverlight]]が[[SOAP]]サーバーと通信するケースが増えたため、追加されたAPI。

-WebClientとの違いは、
--WebRequest, WebResponseの2クラスに分割され、非同期対応がなされた。
--WebResponseを使用してRequestを送信し、CallbackでWebResponseを取得する。

-各クラスには以下の派生クラスがある。
--HttpWebRequest、FileWebRequest、FtpWebRequest
--HttpWebResponse、FileWebResponse、FtpWebResponse

**サンプル [#cc8b82cf]
-.NET CoreのHttpWebRequestについては、~
内部的に[[HttpClientクラス>#n074732e]]をnewしてアクセスしているらしい。

***サンプル [#cc8b82cf]
以下が参考になる。

-DOBON.NET > .NET Tips: C#, VB.NET~
--WebRequest/WebResponseクラスでWebページを取得するには? - @IT~
http://www.atmarkit.co.jp/ait/articles/0506/10/news122.html
--WebRequest、WebResponseクラスを使ってファイルをダウンロードし表示する~
http://dobon.net/vb/dotnet/internet/webrequest.html

**参考 [#nccc74b8]

-MSDN
--WebRequest クラス (System.Net)~
***参考 [#nccc74b8]
-WebRequest クラス (System.Net)~
https://msdn.microsoft.com/ja-jp/library/system.net.webrequest.aspx
--WebResponse クラス (System.Net)~
-WebResponse クラス (System.Net)~
https://msdn.microsoft.com/ja-jp/library/system.net.webresponse.aspx

*jQuery.ajax() [#m5888cea]
HTTPリクエストを使用してデータを取得するajax の最も低レベルな実装。
*参考 [#j377dfef]

以下の様なメソッドも存在する。
-jQuery.get()
-jQuery.post()
**JavaScript [#pc312687]
[[引っ越しました。>https://dotnetdevelopmentinfrastructure.osscons.jp/index.php?JavaScript%20%E3%81%AE%20HTTP%20Client]]

**サンプル [#uaba5c4a]
***POST [#wbcbc8d7]
以下のjQuery.ajaxによるPOSTのサンプル・スニペットを使用すれば色々なパターンを処理可能。
***jQuery.ajax() [#m5888cea]

 $('#btnTest').click(function () {
     $.ajax({
         type: 'post',
         url: 'http://・・・',
         crossDomain: true,
         contentType: 'application/x-www-form-urlencoded',
         headers: {
             'Authorization': 'Bearer ' + token
         },
         data: {
             client_id: '・・・',
             client_secret: '・・・',
         },
         xhrFields: {
             withCredentials: true
         },
         success: function (responseData, textStatus, jqXHR) {
             alert(textStatus + ', ' + responseData);
         },
         error: function (responseData, textStatus, errorThrown) {
             alert(textStatus + ', ' + errorThrown.message);
         }
     });
 });
***, etc. [#y14d9ffa]

***GET [#o77cd2c8]
上記を、GETもイケるよう、改造した。
**障害処理ポリシー [#e8fa9d8f]
***[[Exponential Backoff(指数バックオフ)]] [#h201e45d]
***[[Polly(Retry, Circuit Breaker, Timeout, Bulkhead, Fallback)]] [#n00a0b49]

urlに'get'を、postdataにはnullを指定する。

 function CallOAuthAPI(url, httpMethod, postdata) {
     $.ajax({
         type: httpMethod,
         url: url,
         crossDomain: true,
         headers: {
             'Authorization': 'Bearer ' + token
         },
         data: postdata,
         xhrFields: {
             withCredentials: true
         },
         success: function (responseData, textStatus, jqXHR) {
             alert(textStatus + ', ' + responseData);
         },
         error: function (responseData, textStatus, errorThrown) {
             alert(textStatus + ', ' + errorThrown.message);
         }
     });
 }

***JSON [#o10807ea]
以下は、Web Storageからkey, valueをJSONでPOSTする例。~
JSON文字列へのシリアライズ処理には[[JSON.stringify()>JSONのparseを色々試してみた。#e56c0f75]]を使用する

 // ---------------------------------------------------------------
 // Web Storageからkey, valueをJSONでPOSTする。
 // ---------------------------------------------------------------
 // 引数    url : POST先のURL
 // 戻り値  -
 // ---------------------------------------------------------------
 function PostJsonWebStorage(url) {
     // Web Storageのすべての情報の取得
     var jsonArray = new Array();
 
     for (var i = 0; i < storage.length; i++) {
         var _key = storage.key(i);
 
         // Web Storageのキーと値を表示
         var jsonBean = {
             key: _key,
             value: storage.getItem(_key)
         };
 
         jsonArray.push(jsonBean);
     }
 
     // <p id="url"></p> に表示
     if (document.getElementById("url") != null) {
         $("#url").text(url);
     }
     // <p id="request"></p> に表示
     if (document.getElementById("request") != null) {
         $("#request").text("request:" + JSON.stringify(jsonArray).toString());
     }
 
     CallService("POST", url, JSON.stringify(jsonArray), "application/json; charset=utf-8", "JSON", false);
 }
 
 // ---------------------------------------------------------------
 // ajax
 // ---------------------------------------------------------------
 // 引数
 //         Type : GET or POST or PUT or DELETE verb
 //         Url : Location of the service
 //         Data : Data sent to server
 //         ContentType : Content type sent to server
 //         DataType : Expected data format from server
 //         ProcessData : True or False
 // 戻り値  -
 // ---------------------------------------------------------------
 function CallService(Type, Url, Data, ContentType, DataType, ProcessData) {
     $.ajax({
         type: Type,
         url: Url,
         data: Data,
         cache: false,
         contentType: ContentType,
         dataType: DataType,
         processdata: ProcessData,
         success: function (data) {
             // On Successfull service call
             ServiceSucceeded(data);
         },
         error: function (data) {
             // When Service call fails
             ServiceFailed(data);
         }
     });
 }

**参考 [#id231190]

-jQuery API Documentation
--jQuery.ajax()~
http://api.jquery.com/jquery.ajax/
--jQuery.get()~
http://api.jquery.com/jQuery.get/
--jQuery.post()~
http://api.jquery.com/jQuery.post/

-jQuery 日本語リファレンス
--jQuery.ajax(options) - jQuery 日本語リファレンス~
http://semooh.jp/jquery/api/ajax/jQuery.ajax/options/
--jQuery.get( url, data, callback ) - jQuery 日本語リファレンス~
http://semooh.jp/jquery/api/ajax/jQuery.get/+url%2C+data%2C+callback+/
--jQuery.post( url, data, callback, type ) - ~
http://semooh.jp/jquery/api/ajax/jQuery.post/+url%2C+data%2+callback%2C+type+/

*参考 [#j377dfef]
-ASP.NET Web API シンプルな文字列の POST について - miso_soup3 Blog~
http://miso-soup3.hateblo.jp/entry/2014/06/02/000603
-HttpClient で 認証プロキシ サーバーを使用するには – 荒井省三のBlog~
https://blogs.msdn.microsoft.com/shozoa/2014/09/02/httpclient/
-HttpClient詳解、或いは非同期の落とし穴について~
http://www.slideshare.net/neuecc/httpclient

----
Tags: [[:.NET開発]], [[:.NET Core]], [[:.NET Standard]], [[:ASP.NET]], [[:ASP.NET Web API]]
Tags: [[:プログラミング]], [[:通信技術]], [[:.NET開発]], [[:.NET Core]], [[:ASP.NET]], [[:ASP.NET Web API]]


トップ   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS