HttpClient BaseAddressが機能しないのはなぜですか?


299

BaseAddress部分的なURIパスを定義する次のコードを考えます。

using (var handler = new HttpClientHandler())
using (var client = new HttpClient(handler))
{
    client.BaseAddress = new Uri("http://something.com/api");
    var response = await client.GetAsync("/resource/7");
}

これはへのGETリクエストを実行することを期待していますhttp://something.com/api/resource/7。しかし、そうではありません。

いくつか検索した後、私はこの質問と回答を見つけました:HttpClient with BaseAddress。の/最後に置くことをお勧めしBaseAddressます。

using (var handler = new HttpClientHandler())
using (var client = new HttpClient(handler))
{
    client.BaseAddress = new Uri("http://something.com/api/");
    var response = await client.GetAsync("/resource/7");
}

それでも動作しません。ここにドキュメントがあります:HttpClient.BaseAddressここで何が起こっているのですか?



@ГеоргийЛанец逆複製はすでに提案されています。この質問を具体的に書いたのは、他の質問が同じ問題を抱える人々が非常に見つけやすい方法で書かれていなかったためです。ここで答えを書いたのは、そこにある答えが重要なポイントを残しているからです。
Timothy Shields

しかし、この質問は後で尋ねられます
George Lanetz

2
@ГеоргийЛанецそれはそれがどのように機能するかではありません。通常、最も「標準的な」質問は、重複を指し示す質問です。その別の質問は、FAQのように読むのではなく、ユーザーが抱えていた単一の問題に関するものでした。
Timothy Shields

2
@ГеоргийЛанецまた、私がこの質問の他の質問を参照していること、および他の質問と回答が問題の解決に不十分である理由を説明していることにも注意してください。
Timothy Shields

回答:


719

後続のスラッシュまたは先頭のスラッシュを含めるまたは除外する4つの可能な順列BaseAddressと、GetAsyncメソッドに渡される相対URI、またはその他の方法のいずれかHttpClientで、1つの順列のみが機能することがわかります。あなたはしなければならないの末尾にスラッシュを置きBaseAddress、あなたはしてはならない、次の例のように、あなたの相対URIの先頭にスラッシュを置きます。

using (var handler = new HttpClientHandler())
using (var client = new HttpClient(handler))
{
    client.BaseAddress = new Uri("http://something.com/api/");
    var response = await client.GetAsync("resource/7");
}

私は自分の質問に答えましたが、この不親切な動作は文書化されていないため、ここで解決策を提供すると思いました。同僚と私は1日のほとんどを費やして、このの奇妙さによって最終的に引き起こされた問題を修正しようとしましたHttpClient


4
ありがとうございました。これにより、Azureへの切り替え、IISへの切り替え、IIS Expressへの切り替えなど、2日間ほとんど苦労してきた問題が解決されました。私の基底クラスでセットしたらRestClient、それはほとんど見えなかったし、全く関心を持っていない、と私は私のブレークポイントなどの中に完全なURLを見たことがない
ProfK

43
この奇妙な点(およびこの修正点)が.NET Coreでも依然として関連していることを確認できます。私の髪を引っ張るティモシーを減らしてくれてありがとう。
Nate Barbettini 2017年

8
これは、リクエストをビルドするときに末尾のスラッシュがないと、最後の部分がドロップされるためです。つまり、something.com / resource / 7にヒットします。ベースアドレスをsome / comとして設定した場合(末尾のスラッシュの有無に関係なく)、api / resource / 7の先頭にスラッシュを置いても問題ありません。末尾にスラッシュがないと、ベースアドレスの最後の部分はファイルのように扱われ、要求を大量に送信するとドロップされます。
Piotr Perak 2017年

12
これは元の質問に直接対処するのではなく、関連しています。当たりMircosoft、のHttpClientのインスタンスは、()(静的変数に代入して再利用されるべきであるdocs.microsoft.com/en-us/aspnet/web-api/overview/advanced/... - Creating a new HttpClient instance per request can exhaust the available sockets)。したがって、Using()の削除を検討する必要があります。
sanmcp 2017

6
ただ恐ろしい実装です。なぜこれを修正しないのですか?
timmkrause

55

参照解決は、RFC 3986 Uniform Resource Identifier(URI):Generic Syntaxで説明されています。そして、それはまさにそれが機能するはずであった方法です。ベースURIパスを保持するには、ベースURIの末尾にスラッシュを追加し、相対URIの先頭にあるスラッシュを削除する必要があります。

ベースURIに空でないパスが含まれている場合、マージプロシージャはそれが最後の部分(lastの後/)を破棄します。関連セクション

5.2.3。パスをマージ

上記の擬似コードは、相対パス参照をベースURIのパスとマージするための「マージ」ルーチンを参照しています。これは次のように行われます。

  • ベースURIに定義済みのオーソリティコンポーネントと空のパスがある場合は、参照のパスと連結された「/」で構成される文字列を返します。さもないと

  • ベースURIのパスの最後のセグメントを除くすべてに追加された参照のパスコンポーネントで構成される文字列を返します(つまり、ベースURIパスの右端の "/"の後の文字を除外するか、ベースURIパス全体を除外します) 「/」文字は含まれません)。

相対URIがスラッシュで始まる場合、絶対パス相対URIと呼ばれます。この場合、マージ手順はすべてのベースURIパスを無視します。詳細については、5.2.2を確認してください参照の変換セクション。


3
細かいですが、HttpClientなどのクライアントライブラリは、このような難解な実装の詳細から保護することになっています。
Jamie Ide

-1

HTTPClientの問題に遭遇しました。提案があっても、認証を受けることができませんでした。相対パスに末尾の「/」が必要であることがわかりました。

すなわち

var result = await _client.GetStringAsync(_awxUrl + "api/v2/inventories/?name=" + inventoryName);
var result = await _client.PostAsJsonAsync(_awxUrl + "api/v2/job_templates/" + templateId+"/launch/" , new {
                inventory = inventoryId
            });

-6

またはBaseAddress、まったく使用しないでください。URL全体をGetAsync()に入れます


33
質問にはまったく答えません。
Archibald、

7
BaseAddressはノイズを低減します。とにかく私の目に。:)
MetalMikester

2
私は否定的なコメントに同意しなければならないでしょう。私は2日間かけて、私のHttpClient呼び出しが私のDev PCで機能するのにサーバーで中断する理由を理解しようとしました。奇妙なことにPowershellは機能しますが、.netは機能しません。.SendAsycを使用していました。その後、.GetAsycが機能することを発見しました。これは私を別の道に連れて行き、最終的にここに行きます。ベースアドレスと相対URLの間に/を追加または削除しても何も起こりませんでした。それでも404エラーが発生します。ただし、ベースアドレスを設定せず、パス全体を相対パスに設定しないと、うまくいきました。繰り返しになりますが、これは.SendAsyncを使用したものですが、2日間ありました。
da_jokker
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.