1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【C#】.NET Aspire + YARP で 404 エラー。サービスディスカバリを有効にする正しい HttpClient の扱い方

1
Posted at

はじめに

.NET Aspire を使って、Blazor Web App (BFF) から別サービスの API (Backend) へ YARP でリバースプロキシを張る際、404 Not Found や 502 Bad Gateway に悩まされることがあります。
一見正しいルーティングに見えても、実は HttpClient の作り方一つで名前解決が壊れてしまう という落とし穴についてまとめます。

発生していた現象

以下のような構成で、Blazor Server から Backend サービスへリクエストを転送しようとしました。

参考にしたのは下記ドキュメントです。

// Program.cs の一部
builder.Services.AddHttpForwarderWithServiceDiscovery();

// 自前で HttpClient (HttpMessageInvoker) を作成
var httpClient = new HttpMessageInvoker(new SocketsHttpHandler { /* カスタム設定 */ });

// YARP の MapForwarder で転送設定
app.MapForwarder("/api/{**any}", "https+http://backend", ForwarderRequestConfig.Empty, HttpTransformer.Default, httpClient);

結果: localhost/api/weatherforecast にアクセスすると、Backend サービスに届かず 404 Not Found が返ってくる。

原因:HttpClient が「サービス名」を理解できていない

原因は、MapForwarder に渡した 自作の httpClient にありました。

.NET Aspire では、https+http://backend という特殊な形式(スキーム)を使ってサービスを呼び出しますが、これを実際の IP アドレスや URL に変換するには、Service Discovery 用の MessageHandler が HttpClient のパイプラインに組み込まれている必要があります。

自前で new HttpMessageInvoker(new SocketsHttpHandler()) してしまうと、この「名前解決の仕組み」が一切含まれない "ただの HttpClient" になってしまいます。そのため、YARP は backend という名前のホストを DNS で見つけられず、転送に失敗して 404 を返していたのです。

解決策:YARP の標準機能に任せる

1. 最もシンプルな修正(推奨)

Aspireの場合はMicrosoft.Extensions.ServiceDiscovery.YarpパッケージのAddHttpForwarderWithServiceDiscovery()を使用してすることが必要でなおかつ、MapForwarder の引数で httpClient を指定しなければ、YARP は自動的に Service Discovery 対応済みの HttpClient を内部で使用してくれます。

builder.Services.AddHttpForwarderWithServiceDiscovery();

// 中略

// 引数を省略するだけで OK!
app.MapForwarder("/api/{**any}", "https+http://backend");

2. どうしても HttpClient をカスタマイズしたい場合

もしタイムアウト設定などで httpClient を自作したい場合は、IHttpClientFactory を経由して、Service Discovery が有効なクライアントを取得する必要があります。

Microsoft.Extensions.ServiceDiscovery.Yarpパッケージが必要なのは一緒です。

// builder側で名前解決付きのクライアントを登録
builder.Services.AddHttpClient("MyProxyClient").AddServiceDiscovery();

// MapForwarder 内で factory から取得
app.MapForwarder("/api/{**any}", "https+http://backend", (context, forwarder, factory) => {
    var client = factory.CreateClient("MyProxyClient");
    return forwarder.SendAsync(context, "https+http://backend", client);
});

まとめ

  • Aspire のサービス名 (https+http://...) は、標準の HttpClient では解釈できない。
  • AddHttpForwarderWithServiceDiscovery を使うなら、MapForwarder の引数はできるだけシンプルに保つ(自前で httpClient を渡さない)。
  • カスタマイズが必要な場合は、必ず AddServiceDiscovery() を通した HttpClient を使う。

この記事が皆様のコーディングライフの助けになれば幸いです。

参考

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?