HttpWebRequest から HttpClient への移行ガイド
この記事は、HttpWebRequest、ServicePoint、ServicePointManager から HttpClient に移行するプロセスを開発者に案内することを目的としています。 古い API の陳腐化に対応し、パフォーマンスの向上/リソース管理の向上/よりモダンで柔軟な API 設計といった HttpClient のさまざまなメリットを享受するうえで移行が必要となります。 このドキュメントで説明されている手順に従うことで、開発者はコードベースをスムーズに移行し、HttpClient に用意されている機能を最大限に活用できるようになります。
警告
HttpWebRequest
、ServicePoint
、ServicePointManager
から HttpClient
への移行は、パフォーマンス向上のために「実施しておいた方が良い」というだけではありません。 .NET (Core) への移行後は、既存の WebRequest
ロジックのパフォーマンスが大幅に低下する可能性があることを理解することが重要です。 これは、WebRequest
が最小限の互換性レイヤーとして維持されるためです。つまり、さまざまなケースで接続を再利用するなど、多くの最適化が欠けています。 そのため、アプリケーションのパフォーマンスとリソース管理で最新の標準に準拠するためには、HttpClient
への移行が不可欠です。
HttpWebRequest から HttpClient に移行する
まずはいくつか例を紹介します。
HttpWebRequest を使用するシンプルな GET リクエスト
コードは次のようになります。
HttpWebRequest request = WebRequest.CreateHttp(uri);
using WebResponse response = await request.GetResponseAsync();
HttpClient を使用するシンプルな GET リクエスト
コードは次のようになります。
HttpClient client = new();
using HttpResponseMessage message = await client.GetAsync(uri);
HttpWebRequest を使用するシンプルな POST リクエスト
コードは次のようになります。
HttpWebRequest request = WebRequest.CreateHttp(uri);
request.Method = "POST";
request.ContentType = "text/plain";
await using Stream stream = await request.GetRequestStreamAsync();
await stream.WriteAsync("Hello World!"u8.ToArray());
using WebResponse response = await request.GetResponseAsync();
HttpClient を使用するシンプルな POST リクエスト
コードは次のようになります。
HttpClient client = new();
using HttpResponseMessage responseMessage = await client.PostAsync(uri, new StringContent("Hello World!"));
HttpWebRequest から HttpClient、SocketsHttpHandler 移行ガイド
HttpWebRequest 古い API | 新しい API | メモ |
---|---|---|
Accept |
Accept | 例: 要求ヘッダーを設定する。 |
Address |
RequestUri | 例: リダイレクトされた URI を取得する。 |
AllowAutoRedirect |
AllowAutoRedirect | 例: SocketsHttpHandler プロパティの設定。 |
AllowReadStreamBuffering |
同等の API なし | バッファリング プロパティの使用。 |
AllowWriteStreamBuffering |
同等の API なし | バッファリング プロパティの使用。 |
AuthenticationLevel |
同等の API なし | 例: 相互認証の有効化。 |
AutomaticDecompression |
AutomaticDecompression | 例: SocketsHttpHandler プロパティの設定。 |
CachePolicy |
同等の API なし | 例: CachePolicy ヘッダーを適用する。 |
ClientCertificates |
ClientCertificates= | HttpClient における証明書関連プロパティの使用。 |
Connection |
Connection | 例: 要求ヘッダーを設定する。 |
ConnectionGroupName |
同等の API なし | 回避策なし |
ContentLength |
ContentLength | 例: コンテンツ ヘッダーを設定する。 |
ContentType |
ContentType | 例: コンテンツ ヘッダーを設定する。 |
ContinueDelegate |
同等の API なし | 回避策はありません。 |
ContinueTimeout |
Expect100ContinueTimeout | 例: SocketsHttpHandler プロパティの設定。 |
CookieContainer |
CookieContainer | 例: SocketsHttpHandler プロパティの設定。 |
Credentials |
Credentials | 例: SocketsHttpHandler プロパティの設定。 |
Date |
Date | 例: 要求ヘッダーを設定する。 |
DefaultCachePolicy |
同等の API なし | 例: CachePolicy ヘッダーを適用する。 |
DefaultMaximumErrorResponseLength |
同等の API なし | 例: HttpClient で MaximumErrorResponseLength を設定する。 |
DefaultMaximumResponseHeadersLength |
同等の API なし | 代わりに MaxResponseHeadersLength を使用できます。 |
DefaultWebProxy |
同等の API なし | 代わりに Proxy を使用できます。 |
Expect |
Expect | 例: 要求ヘッダーを設定する。 |
HaveResponse |
同等の API なし | HttpResponseMessage インスタンスを持つことによって暗黙的に指定されます。 |
Headers |
Headers | 例: 要求ヘッダーを設定する。 |
Host |
Host | 例: 要求ヘッダーを設定する。 |
IfModifiedSince |
IfModifiedSince | 例: 要求ヘッダーを設定する。 |
ImpersonationLevel |
同等の API なし | 例: ImpersonationLevel を変更する。 |
KeepAlive |
同等の API なし | 例: 要求ヘッダーを設定する。 |
MaximumAutomaticRedirections |
MaxAutomaticRedirections | 例: SocketsHttpHandler プロパティの設定。 |
MaximumResponseHeadersLength |
MaxResponseHeadersLength | 例: SocketsHttpHandler プロパティの設定。 |
MediaType |
同等の API なし | 例: コンテンツ ヘッダーを設定する。 |
Method |
Method | 例: HttpRequestMessage プロパティの使用。 |
Pipelined |
同等の API なし | HttpClient ではパイプライン処理がサポートされていません。 |
PreAuthenticate |
PreAuthenticate | |
ProtocolVersion |
HttpRequestMessage.Version |
例: HttpRequestMessage プロパティの使用。 |
Proxy |
Proxy | 例: SocketsHttpHandler プロパティの設定。 |
ReadWriteTimeout |
同等の API なし | SocketsHttpHandler と ConnectCallback の使用。 |
Referer |
Referrer | 例: 要求ヘッダーを設定する。 |
RequestUri |
RequestUri | 例: HttpRequestMessage プロパティの使用。 |
SendChunked |
TransferEncodingChunked | 例: 要求ヘッダーを設定する。 |
ServerCertificateValidationCallback |
RemoteCertificateValidationCallback= | 例: SocketsHttpHandler プロパティの設定。 |
ServicePoint |
同等の API なし | ServicePoint は HttpClient の一部ではありません。 |
SupportsCookieContainer |
同等の API なし | HttpClient の場合、これは常に true です。 |
Timeout |
Timeout | |
TransferEncoding |
TransferEncoding | 例: 要求ヘッダーを設定する。 |
UnsafeAuthenticatedConnectionSharing |
同等の API なし | 回避策なし |
UseDefaultCredentials |
同等の API なし | 例: SocketsHttpHandler プロパティの設定。 |
UserAgent |
UserAgent | 例: 要求ヘッダーを設定する。 |
ServicePoint(Manager) の使用状況の移行
ServicePointManager
は静的クラスであるため、プロパティに加えられた変更は、アプリケーション内で新しく作成されたすべての ServicePoint
オブジェクトにグローバルな影響を与える点に注意する必要があります。 たとえば、ConnectionLimit
や Expect100Continue
などのプロパティに変更を加えると、すべての新しい ServicePoint インスタンスに影響します。
警告
最新の .NET において、HttpClient
では ServicePointManager
に設定された構成は考慮されません。
ServicePointManager プロパティのマッピング
ServicePointManager古い API | 新しい API | メモ |
---|---|---|
CheckCertificateRevocationList |
CertificateRevocationCheckMode= | 例: SocketsHttpHandler を使用した CRL チェックの有効化。 |
DefaultConnectionLimit |
MaxConnectionsPerServer | 例: SocketsHttpHandler プロパティの設定。 |
DnsRefreshTimeout |
同等の API なし | 例: Dns ラウンド ロビンの有効化。 |
EnableDnsRoundRobin |
同等の API なし | 例: Dns ラウンド ロビンの有効化。 |
EncryptionPolicy |
EncryptionPolicy= | 例: SocketsHttpHandler プロパティの設定。 |
Expect100Continue |
ExpectContinue | 例: 要求ヘッダーを設定する。 |
MaxServicePointIdleTime |
PooledConnectionIdleTimeout | 例: SocketsHttpHandler プロパティの設定。 |
MaxServicePoints |
同等の API なし | ServicePoint は HttpClient の一部ではありません。 |
ReusePort |
同等の API なし | SocketsHttpHandler と ConnectCallback の使用。 |
SecurityProtocol |
EnabledSslProtocols= | 例: SocketsHttpHandler プロパティの設定。 |
ServerCertificateValidationCallback |
RemoteCertificateValidationCallback= | これらはいずれも RemoteCertificateValidationCallback |
UseNagleAlgorithm |
同等の API なし | SocketsHttpHandler と ConnectCallback の使用。 |
警告
最新の .NET では、UseNagleAlgorithm
プロパティと Expect100Continue
プロパティの既定値が false
に設定されています。 これらの値は、.NET Framework では既定で true
でした。
ServicePointManager メソッドのマッピング
ServicePointManager古い API | 新しい API | メモ |
---|---|---|
FindServicePoint |
同等の API なし | 回避策なし |
SetTcpKeepAlive |
同等の API なし | SocketsHttpHandler と ConnectCallback の使用。 |
ServicePoint プロパティのマッピング
ServicePoint古い API | 新しい API | メモ |
---|---|---|
Address |
HttpRequestMessage.RequestUri |
これは要求 URI です。この情報は HttpRequestMessage にあります。 |
BindIPEndPointDelegate |
同等の API なし | SocketsHttpHandler と ConnectCallback の使用。 |
Certificate |
同等の API なし | この情報は RemoteCertificateValidationCallback から取得できます。 例: 証明書を取得する。 |
ClientCertificate |
同等の API なし | 例: 相互認証の有効化。 |
ConnectionLeaseTimeout |
SocketsHttpHandler.PooledConnectionLifetime |
HttpClient の同等の設定 |
ConnectionLimit |
MaxConnectionsPerServer | 例: SocketsHttpHandler プロパティの設定。 |
ConnectionName |
同等の API なし | 回避策なし |
CurrentConnections |
同等の API なし | .NET ドキュメントのネットワーキング テレメトリ。 |
Expect100Continue |
ExpectContinue | 例: 要求ヘッダーを設定する。 |
IdleSince |
同等の API なし | 回避策なし |
MaxIdleTime |
PooledConnectionIdleTimeout | 例: SocketsHttpHandler プロパティの設定。 |
ProtocolVersion |
HttpRequestMessage.Version |
例: HttpRequestMessage プロパティの使用。 |
ReceiveBufferSize |
同等の API なし | SocketsHttpHandler と ConnectCallback の使用。 |
SupportsPipelining |
同等の API なし | HttpClient ではパイプライン処理がサポートされていません。 |
UseNagleAlgorithm |
同等の API なし | SocketsHttpHandler と ConnectCallback の使用。 |
ServicePoint メソッドのマッピング
ServicePoint古い API | 新しい API | メモ |
---|---|---|
CloseConnectionGroup |
同等の機能がありません | 回避策なし |
SetTcpKeepAlive |
同等の API なし | SocketsHttpHandler と ConnectCallback の使用。 |
HttpClient プロパティと HttpRequestMessage プロパティの使用
.NET で HttpClient を使用する場合は、HTTP の要求と応答を構成およびカスタマイズできるさまざまなプロパティにアクセスできます。 これらのプロパティを理解することで、HttpClient を最大限に活用し、アプリケーションが Web サービスと効率的かつ安全に通信できるようになります。
例: HttpRequestMessage プロパティの使用
HttpClient と HttpRequestMessage を併用する方法の例を次に示します。
var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Post, "https://example.com"); // Method and RequestUri usage
var request = new HttpRequestMessage() // Alternative way to set RequestUri and Method
{
RequestUri = new Uri("https://example.com"),
Method = HttpMethod.Post
};
request.Headers.Add("Custom-Header", "value");
request.Content = new StringContent("somestring");
using var response = await client.SendAsync(request);
var protocolVersion = response.RequestMessage.Version; // Fetch `ProtocolVersion`.
例: リダイレクトされた URI を取得する
リダイレクトされた URI を取得する方法の例を次に示します (HttpWebRequest.Address
と同じ)。
var client = new HttpClient();
using var response = await client.GetAsync(uri);
var redirectedUri = response.RequestMessage.RequestUri;
SocketsHttpHandler と ConnectCallback の使用
SocketsHttpHandler
の ConnectCallback
プロパティを使用すると、開発者は TCP 接続を確立するプロセスをカスタマイズできます。 これは、DNS 解決を制御したり、接続に特定のソケット オプションを適用したりする必要があるシナリオに役立ちます。 ConnectCallback
を使用すると、接続プロセスをインターセプトして変更してから HttpClient
で使用できます。
例: ソケットへの IP アドレスのバインド
HttpWebRequest
を使用する以前のアプローチでは、カスタム ロジックを使用して特定の IP アドレスをソケットにバインドすることもありました。 HttpClient
と ConnectCallback
を使用して同様の機能を実現する方法を次に示します。
HttpWebRequest
を使用した古いコード:
HttpWebRequest request = WebRequest.CreateHttp(uri);
request.ServicePoint.BindIPEndPointDelegate = (servicePoint, remoteEndPoint, retryCount) =>
{
// Bind to a specific IP address
IPAddress localAddress = IPAddress.Parse("192.168.1.100");
return new IPEndPoint(localAddress, 0);
};
using HttpWebResponse response = (HttpWebResponse)request.GetResponse();
HttpClient
と ConnectCallback
を使用した新しいコード:
var handler = new SocketsHttpHandler
{
ConnectCallback = async (context, cancellationToken) =>
{
// Bind to a specific IP address
IPAddress localAddress = IPAddress.Parse("192.168.1.100");
var socket = new Socket(localAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
try
{
socket.Bind(new IPEndPoint(localAddress, 0));
await socket.ConnectAsync(context.DnsEndPoint, cancellationToken);
return new NetworkStream(socket, ownsSocket: true);
}
catch
{
socket.Dispose();
throw;
}
}
};
var client = new HttpClient(handler);
using var response = await client.GetAsync(uri);
例: 特定のソケット オプションの適用
TCP キープアライブの有効化など、特定のソケット オプションを適用する必要がある場合は、HttpClient
で使用する前に、ConnectCallback
を使用してソケットを構成できます。 実際、ConnectCallback
の方がソケット オプションを柔軟に構成できます。
HttpWebRequest
を使用した古いコード:
ServicePointManager.ReusePort = true;
HttpWebRequest request = WebRequest.CreateHttp(uri);
request.ServicePoint.SetTcpKeepAlive(true, 60000, 1000);
request.ServicePoint.ReceiveBufferSize = 8192;
request.ServicePoint.UseNagleAlgorithm = false;
using HttpWebResponse response = (HttpWebResponse)request.GetResponse();
HttpClient
と ConnectCallback
を使用した新しいコード:
var handler = new SocketsHttpHandler
{
ConnectCallback = async (context, cancellationToken) =>
{
var socket = new Socket(SocketType.Stream, ProtocolType.Tcp);
try
{
// Setting TCP Keep Alive
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);
socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.TcpKeepAliveTime, 60);
socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.TcpKeepAliveInterval, 1);
// Setting ReceiveBufferSize
socket.ReceiveBufferSize = 8192;
// Enabling ReusePort
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseUnicastPort, true);
// Disabling Nagle Algorithm
socket.NoDelay = true;
await socket.ConnectAsync(context.DnsEndPoint, cancellationToken);
return new NetworkStream(socket, ownsSocket: true);
}
catch
{
socket.Dispose();
throw;
}
}
};
var client = new HttpClient(handler);
using var response = await client.GetAsync(uri);
例: DNS ラウンド ロビンを有効にする
DNS ラウンド ロビンは、1 つのドメイン名に関連付けられている IP アドレスのリストをローテーションして、複数のサーバー間でネットワーク トラフィックを分散するために使用される手法です。 これは、負荷分散とサービスの可用性の向上に役立ちます。 HttpClient を使用する場合、DNS ラウンド ロビンを実装するには、手動で DNS 解決を処理し、SocketsHttpHandler の ConnectCallback プロパティを使用して IP アドレスをローテーションします。
HttpClient で DNS ラウンド ロビンを有効にするには、ConnectCallback プロパティを使用して DNS エントリを手動で解決し、IP アドレスをローテーションします。 HttpWebRequest
と HttpClient
の例を次に示します。
HttpWebRequest
を使用した古いコード:
ServicePointManager.DnsRefreshTimeout = 60000;
ServicePointManager.EnableDnsRoundRobin = true;
HttpWebRequest request = WebRequest.CreateHttp(uri);
using HttpWebResponse response = (HttpWebResponse)request.GetResponse();
以前の HttpWebRequest
API では、この機能の組み込みサポートにより、DNS ラウンド ロビンの有効化は簡単でした。 ただし、新しい HttpClient
API では同じ組み込み機能は提供されていません。 それでも、DNS 解決によって返される IP アドレスを手動でローテーションする DnsRoundRobinConnector
を実装することで、同様の動作を実現できます。
HttpClient
を使用した新しいコード:
// This is available as NuGet Package: https://www.nuget.org/packages/DnsRoundRobin/
// The original source code can be found also here: https://github.com/MihaZupan/DnsRoundRobin
public sealed class DnsRoundRobinConnector : IDisposable
DnsRoundRobinConnector
の実装についてはこちらを参照してください。
DnsRoundRobinConnector
使用:
private static readonly DnsRoundRobinConnector s_roundRobinConnector = new(
dnsRefreshInterval: TimeSpan.FromSeconds(10),
endpointConnectTimeout: TimeSpan.FromSeconds(5));
static async Task DnsRoundRobinConnectAsync()
{
var handler = new SocketsHttpHandler
{
ConnectCallback = async (context, cancellation) =>
{
Socket socket = await DnsRoundRobinConnector.Shared.ConnectAsync(context.DnsEndPoint, cancellation);
// Or you can create and use your custom DnsRoundRobinConnector instance
// Socket socket = await s_roundRobinConnector.ConnectAsync(context.DnsEndPoint, cancellation);
return new NetworkStream(socket, ownsSocket: true);
}
};
var client = new HttpClient(handler);
HttpResponseMessage response = await client.GetAsync(Uri);
}
例: SocketsHttpHandler プロパティの設定
SocketsHttpHandler は、HTTP 接続を管理するための高度な構成オプションを提供する、.NET の強力で柔軟なハンドラーです。 SocketsHttpHandler のさまざまなプロパティを設定することで、パフォーマンスの最適化、セキュリティの強化、カスタム接続処理など、特定の要件を満たすように HTTP クライアントの動作を微調整できます。
さまざまなプロパティで SocketsHttpHandler を構成し、HttpClient で使用する方法の例を次に示します。
var cookieContainer = new CookieContainer();
cookieContainer.Add(new Cookie("cookieName", "cookieValue"));
var handler = new SocketsHttpHandler
{
AllowAutoRedirect = true,
AutomaticDecompression = DecompressionMethods.All,
Expect100ContinueTimeout = TimeSpan.FromSeconds(1),
CookieContainer = cookieContainer,
Credentials = new NetworkCredential("user", "pass"),
MaxAutomaticRedirections = 10,
MaxResponseHeadersLength = 1,
Proxy = new WebProxy("http://proxyserver:8080"), // Don't forget to set UseProxy
UseProxy = true,
};
var client = new HttpClient(handler);
using var response = await client.GetAsync(uri);
例: ImpersonationLevel を変更する
この機能は特定のプラットフォームに固有であり、やや古くなっています。 回避策が必要な場合は、コードのこのセクションを参照してください。
HttpClient における証明書と TLS 関連プロパティの使用
HttpClient
を使用する場合は、サーバー証明書のカスタム検証やサーバー証明書の取得など、さまざまな目的でクライアント証明書を処理することが必要になる場合があります。 HttpClient
には、証明書を効率的に管理するためのプロパティとオプションがいくつか用意されています。
例: SocketsHttpHandler を使用して証明書失効リストをチェックする
SocketsHttpHandler.SslOptions
の CheckCertificateRevocationList
プロパティを使用すると、開発者は SSL/TLS ハンドシェイク中に証明書失効リスト (CRL) のチェックを有効または無効にすることができます。 このプロパティを有効にすると、クライアントはサーバーの証明書が失効しているかどうかを確認するため、接続のセキュリティが強化されます。
HttpWebRequest
を使用した古いコード:
ServicePointManager.CheckCertificateRevocationList = true;
HttpWebRequest request = WebRequest.CreateHttp(uri);
using HttpWebResponse response = (HttpWebResponse)request.GetResponse();
HttpClient
を使用した新しいコード:
bool checkCertificateRevocationList = true;
var handler = new SocketsHttpHandler
{
SslOptions =
{
CertificateRevocationCheckMode = checkCertificateRevocationList ? X509RevocationMode.Online : X509RevocationMode.NoCheck,
}
};
var client = new HttpClient(handler);
using var response = await client.GetAsync(uri);
例: 証明書を取得する
HttpClient
の RemoteCertificateValidationCallback
から証明書を取得するには、HttpClientHandler
または SocketsHttpHandler.SslOptions
の ServerCertificateCustomValidationCallback
プロパティを使用します。 このコールバックを使用すると、SSL/TLS ハンドシェイク中にサーバーの証明書を検査できます。
HttpWebRequest
を使用した古いコード:
HttpWebRequest request = WebRequest.CreateHttp(uri);
using HttpWebResponse response = (HttpWebResponse)request.GetResponse();
X509Certificate? serverCertificate = request.ServicePoint.Certificate;
HttpClient
を使用した新しいコード:
X509Certificate? serverCertificate = null;
var handler = new SocketsHttpHandler
{
SslOptions = new SslClientAuthenticationOptions
{
RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) =>
{
serverCertificate = certificate;
// Leave the validation as-is.
return sslPolicyErrors == SslPolicyErrors.None;
}
}
};
var client = new HttpClient(handler);
using var response = await client.GetAsync("https://example.com");
例: 相互認証を有効にする
相互認証 (双方向 SSL またはクライアント証明書認証とも呼ばれます) は、クライアントとサーバーの両方が相互に認証を行うセキュリティ プロセスです。 これにより、両当事者の本人確認が行われ、機密性の高い通信のセキュリティが強化されます。 HttpClient
では、クライアント証明書を含めてサーバーの証明書を検証するように HttpClientHandler
または SocketsHttpHandler
を構成することで、相互認証を有効にすることができます。
相互認証を有効にするには、次の手順を実行します。
- クライアント証明書を読み込みます。
- クライアント証明書を含むように HttpClientHandler または SocketsHttpHandler を構成します。
- カスタム検証が必要な場合は、サーバー証明書検証コールバックを設定します。
SocketsHttpHandler を使用した例を次に示します。
var handler = new SocketsHttpHandler
{
SslOptions = new SslClientAuthenticationOptions
{
ClientCertificates = new X509CertificateCollection
{
// Load the client certificate from a file
new X509Certificate2("path_to_certificate.pfx", "certificate_password")
},
RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) =>
{
// Custom validation logic for the server certificate
return sslPolicyErrors == SslPolicyErrors.None;
}
}
};
var client = new HttpClient(handler);
using var response = await client.GetAsync(uri);
ヘッダー プロパティの使用
ヘッダーは HTTP 通信において重要な役割を果たし、要求と応答に関する必要不可欠なメタデータを提供します。 .NET で HttpClient
を使用する場合は、さまざまなヘッダー プロパティを設定および管理して、HTTP の要求と応答の動作を制御できます。 これらのヘッダー プロパティを効果的に使用する方法を理解すると、アプリケーションが Web サービスと効率的かつ安全に通信できるようになります。
要求ヘッダーを設定する
要求ヘッダーは、行われる要求に関する追加情報をサーバーに提供するために使用されます。 一般的なユース ケースとしては、コンテンツ タイプの指定、認証トークンの設定、カスタム ヘッダーの追加などがあります。 要求ヘッダーは、HttpClient
の DefaultRequestHeaders
プロパティまたは HttpRequestMessage
の Headers プロパティを使用して設定できます。
例: カスタム要求ヘッダーを設定する
HttpClient での既定のカスタム要求ヘッダーの設定
var client = new HttpClient();
client.DefaultRequestHeaders.Add("Custom-Header", "value");
HttpRequestMessage でのカスタム要求ヘッダーの設定
var request = new HttpRequestMessage(HttpMethod.Get, uri);
request.Headers.Add("Custom-Header", "value");
例: 共通要求ヘッダーを設定する
.NET で HttpRequestMessage
を使用する場合、行われる要求に関する追加情報をサーバーに提供するには、共通要求ヘッダーを設定することが不可欠です。 これらのヘッダーには認証トークンなどを含めることができます。 これらのヘッダーを適切に構成すると、サーバーによって HTTP 要求が正しく処理されます。
HttpRequestHeaders で使用できる共通プロパティの包括的なリストについては、「プロパティ」を参照してください。
HttpRequestMessage
で共通要求ヘッダーを設定するには、HttpRequestMessage
オブジェクトの Headers
プロパティを使用します。 このプロパティは、必要に応じてヘッダーを追加または変更できる HttpRequestHeaders
コレクションへのアクセスを提供します。
HttpClient での共通の既定要求ヘッダーの設定
using System.Net.Http.Headers;
var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "token");
HttpRequestMessage での共通要求ヘッダーの設定
using System.Net.Http.Headers;
var request = new HttpRequestMessage(HttpMethod.Get, uri);
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", "token");
例: コンテンツ ヘッダーを設定する
コンテンツ ヘッダーは、HTTP の要求または応答の本文に関する追加情報を提供するために使用されます。 .NET で HttpClient
を使用する場合は、コンテンツ ヘッダーを設定して、送受信するコンテンツに関連するメディアの種類、エンコード、およびその他のメタデータを指定できます。 コンテンツ ヘッダーを適切に構成すると、サーバーとクライアントがコンテンツを正しく解釈して処理できるようになります。
var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Post, uri);
// Create the content and set the content headers
var jsonData = "{\"key\":\"value\"}";
var content = new StringContent(jsonData, Encoding.UTF8, "application/json");
// The following headers are set automatically by `StringContent`. If you wish to override their values, you can do it like so:
// content.Headers.ContentType = new MediaTypeHeaderValue("application/json; charset=utf-8");
// content.Headers.ContentLength = Encoding.UTF8.GetByteCount(jsonData);
// Assign the content to the request
request.Content = content;
using var response = await client.SendAsync(request);
例: HttpClient で MaximumErrorResponseLength を設定する
MaximumErrorResponseLength
を使用することで、ハンドラーがバッファリングするエラー応答コンテンツの最大長を開発者が指定できます。 これは、エラー応答がサーバーから受信されたときにメモリに読み取られて格納されるデータの量を制御するのに役立ちます。 この手法を使用すると、大量のエラー応答を処理するときに、過剰なメモリの使用を防ぎ、アプリケーションのパフォーマンスを向上させることができます。
これを行う方法はいくつかあります。この例では TruncatedReadStream
手法について説明します。
internal sealed class TruncatedReadStream(Stream innerStream, long maxSize) : Stream
{
private long _maxRemainingLength = maxSize;
public override bool CanRead => true;
public override bool CanSeek => false;
public override bool CanWrite => false;
public override long Length => throw new NotSupportedException();
public override long Position { get => throw new NotSupportedException(); set => throw new NotSupportedException(); }
public override void Flush() => throw new NotSupportedException();
public override int Read(byte[] buffer, int offset, int count)
{
return Read(new Span<byte>(buffer, offset, count));
}
public override int Read(Span<byte> buffer)
{
int readBytes = innerStream.Read(buffer.Slice(0, (int)Math.Min(buffer.Length, _maxRemainingLength)));
_maxRemainingLength -= readBytes;
return readBytes;
}
public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
return ReadAsync(new Memory<byte>(buffer, offset, count), cancellationToken).AsTask();
}
public override async ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken cancellationToken = default)
{
int readBytes = await innerStream.ReadAsync(buffer.Slice(0, (int)Math.Min(buffer.Length, _maxRemainingLength)), cancellationToken)
.ConfigureAwait(false);
_maxRemainingLength -= readBytes;
return readBytes;
}
public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException();
public override void SetLength(long value) => throw new NotSupportedException();
public override void Write(byte[] buffer, int offset, int count) => throw new NotSupportedException();
public override ValueTask DisposeAsync() => innerStream.DisposeAsync();
protected override void Dispose(bool disposing)
{
if (disposing)
{
innerStream.Dispose();
}
}
}
TruncatedReadStream
の使用例:
int maxErrorResponseLength = 1 * 1024; // 1 KB
HttpClient client = new HttpClient();
using HttpResponseMessage response = await client.GetAsync(Uri);
if (response.Content is not null)
{
Stream responseReadStream = await response.Content.ReadAsStreamAsync();
// If MaxErrorResponseLength is set and the response status code is an error code, then wrap the response stream in a TruncatedReadStream
if (maxErrorResponseLength >= 0 && !response.IsSuccessStatusCode)
{
responseReadStream = new TruncatedReadStream(responseReadStream, maxErrorResponseLength);
}
// Read the response stream
Memory<byte> buffer = new byte[1024];
int readValue = await responseReadStream.ReadAsync(buffer);
}
例: CachePolicy ヘッダーを適用する
警告
HttpClient
には応答をキャッシュするロジックが組み込まれていません。 すべてのキャッシュを自分で実装する以外の回避策はありません。 ヘッダーを設定するだけではキャッシュは実現されません。
HttpWebRequest
から HttpClient
に移行する場合は、pragma
や cache-control
などのキャッシュ関連のヘッダーを正しく処理することが重要です。 これらのヘッダーは応答のキャッシュ方法と取得方法を制御し、パフォーマンスとデータの鮮度の観点からアプリケーションが期待どおりに動作することを保証します。
HttpWebRequest
では、CachePolicy
プロパティを使用してこれらのヘッダーを設定していた場合もあります。 ただし、HttpClient
では、要求でこれらのヘッダーを手動で設定する必要があります。
HttpWebRequest
を使用した古いコード:
HttpWebRequest request = WebRequest.CreateHttp(uri);
request.CachePolicy = new HttpRequestCachePolicy(HttpRequestCacheLevel.NoCacheNoStore);
using HttpWebResponse response = (HttpWebResponse)request.GetResponse();
以前の HttpWebRequest
API では、この機能の組み込みサポートにより CachePolicy
の適用は簡単でした。 ただし、新しい HttpClient
API では同じ組み込み機能は提供されていません。 それでも、キャッシュ関連のヘッダーを手動で追加する AddCacheControlHeaders
を実装することで、同様の動作を実現できます。
HttpClient
を使用した新しいコード:
public static class CachePolicy
{
public static void AddCacheControlHeaders(HttpRequestMessage request, RequestCachePolicy policy)
AddCacheControlHeaders
の実装についてはこちらを参照してください。
AddCacheControlHeaders
使用:
static async Task AddCacheControlHeaders()
{
HttpClient client = new HttpClient();
HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Get, Uri);
CachePolicy.AddCacheControlHeaders(requestMessage, new HttpRequestCachePolicy(HttpRequestCacheLevel.NoCacheNoStore));
HttpResponseMessage response = await client.SendAsync(requestMessage);
}
バッファリング プロパティの使用
HttpWebRequest から HttpClient
に移行する場合は、これら 2 つの API におけるバッファリング方法の違いを理解することが重要です。
HttpWebRequest
を使用した古いコード:
HttpWebRequest
では、AllowWriteStreamBuffering
プロパティと AllowReadStreamBuffering
プロパティを使用してバッファリング プロパティを直接制御できます。 これらのプロパティは、サーバーとの間で送受信されるデータのバッファリングを有効または無効にします。
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
request.AllowReadStreamBuffering = true; // Default is `false`.
request.AllowWriteStreamBuffering = false; // Default is `true`.
HttpClient
を使用した新しいコード:
HttpClient
では、AllowWriteStreamBuffering
プロパティと AllowReadStreamBuffering
プロパティに直接相当するものはありません。
HttpClient は、要求本文を単独でバッファリングするのではなく、使用される HttpContent
に責任を委任します。 StringContent
や ByteArrayContent
などのコンテンツは論理的に既にメモリにバッファリングされていますが、StreamContent
を使用しても、既定ではバッファリングは発生しません。 コンテンツを強制的にバッファリングするには、要求を送信する前に HttpContent.LoadIntoBufferAsync
を呼び出します。 次に例を示します。
HttpClient client = new HttpClient();
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, uri);
request.Content = new StreamContent(yourStream);
await request.Content.LoadIntoBufferAsync();
HttpResponseMessage response = await client.SendAsync(request);
HttpClient
では、既定で読み取りバッファリングが有効になっています。 これを回避するには、HttpCompletionOption.ResponseHeadersRead
フラグを指定するか、GetStreamAsync
ヘルパーを使用します。
HttpClient client = new HttpClient();
using HttpResponseMessage response = await client.GetAsync(uri, HttpCompletionOption.ResponseHeadersRead);
await using Stream responseStream = await response.Content.ReadAsStreamAsync();
// Or simply
await using Stream responseStream = await client.GetStreamAsync(uri);
.NET