539 Stimmen

Warum funktioniert HttpClient BaseAddress nicht?

Betrachten Sie den folgenden Code, in dem BaseAddress einen Teilpfad der URI definiert.

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");
}

Ich erwarte, dass dies eine GET-Anfrage an http://something.com/api/resource/7 ausführt. Aber das tut es nicht.

Nach einigem Suchen finde ich diese Frage und Antwort: HttpClient with BaseAddress. Der Vorschlag ist, / am Ende des BaseAddress zu platzieren.

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");
}

Es funktioniert immer noch nicht. Hier ist die Dokumentation: HttpClient.BaseAddress Was passiert hier?

1303voto

Timothy Shields Punkte 70194

Es stellt sich heraus, dass von den vier möglichen Permutationen von einschließen oder ausschließen von nachgestellten oder führenden Schrägstrichen in der BaseAddress und der relativen URI, die an die GetAsync Methode übergeben werden - oder an jede andere Methode des HttpClient - nur eine Permutation funktioniert. Du musst einen Schrägstrich am Ende der BaseAddress platzieren, und du darfst nicht einen Schrägstrich am Anfang deiner relativen URI platzieren, wie im folgenden Beispiel.

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");
}

Auch wenn ich meine eigene Frage beantwortet habe, dachte ich, ich würde die Lösung hier beitragen, da dieses unfreundliche Verhalten erneut undokumentiert ist. Mein Kollege und ich haben den größten Teil des Tages damit verbracht, ein Problem zu lösen, das letztendlich durch diese Eigenart des HttpClient verursacht wurde.

137voto

Leonid Vasilev Punkte 10814

Die Referenzauflösung wird von RFC 3986 Uniform Resource Identifier (URI): Generische Syntax beschrieben. Und genau so soll es funktionieren. Um den Basis-URI-Pfad beizubehalten, müssen Sie am Ende des Basis-URI einen Schrägstrich hinzufügen und am Anfang des relativen URI entfernen.

Wenn der Basis-URI einen nicht leeren Pfad enthält, verwirft das Merge-Verfahren seinen letzten Teil (nach dem letzten /). Der relevante Abschnitt:

5.2.3. Pfade verschmelzen

Der oben dargestellte Pseudocode bezieht sich auf eine "Verschmelzungs"-Routine zum Verschmelzen eines relativen Pfadverweises mit dem Pfad des Basis-URI. Dies wird wie folgt erreicht:

  • Wenn der Basis-URI einen definierten Autoritätsbestandteil und einen leeren Pfad hat, geben Sie eine Zeichenfolge zurück, die aus "/" zusammen mit dem Pfad des Verweises besteht; sonst

  • geben Sie eine Zeichenfolge zurück, die aus dem Pfadbestandteil des Verweises angehängt wird an alles außer dem letzten Segment des Pfads des Basis-URI (d.h., ohne Zeichen nach dem rechtesten "/" im Pfad des Basis-URI oder ohne den gesamten Pfad des Basis-URI, wenn er keine "/" Zeichen enthält).

Wenn der relative URI mit einem Schrägstrich beginnt, wird er als absoluter Pfadrelativer URI bezeichnet. In diesem Fall ignoriert das Verschmelzungsverfahren den gesamten Basis-URI-Pfad. Weitere Informationen finden Sie im Abschnitt 5.2.2. Verweise transformieren.

19voto

Iman Punkte 16668

Wenn Sie httpClient.SendAsync() verwenden, gibt es keine Zeichenfolgenüberladung für die Angabe von relativen URIs wie bei den Überladungen für Get oder andere verb-spezifische Methoden.

Aber Sie können einen relativen Uri erstellen, indem Sie UriKind.Relative als zweiten Parameter angeben

var httpRequestMessage = new HttpRequestMessage
{
    Method = httpMethod,
    RequestUri = new Uri(relativeRequestUri, UriKind.Relative),
    Content = content
};

using var httpClient = HttpClientFactory.CreateClient("XClient");
var response = await httpClient.SendAsync(httpRequestMessage);
var responseText = await response.Content.ReadAsStringAsync();

5voto

kiko283 Punkte 490

Ich bin auch auf dasselbe Problem mit BaseAddress gestoßen. Ich habe mich entschieden, BaseAddress überhaupt nicht zu verwenden, und die einfachste Lösung wäre eine einfache einzeilige Ergänzung:

Uri GetUri(string path) => new Uri("http://something.com/api" + path);

Dann würde Ihr Code folgendermaßen aussehen:

Uri GetUri(string path) => new Uri("http://something.com/api" + path);
using (var handler = new HttpClientHandler())
using (var client = new HttpClient(handler))
{
    // Entfernen Sie die BaseAddress komplett
    // client.BaseAddress = new Uri("http://something.com/api");
    var response = await client.GetAsync(GetUri("/resource/7"));
}

Ich habe die Vor- und Nachteile der Verwendung von BaseAddress im Vergleich dazu nicht untersucht, aber für mich funktioniert dies einwandfrei. Ich hoffe, dass dies jemandem hilft.

0voto

Tony Punkte 17

Bin auf ein Problem mit dem HTTPClient gestoßen, auch mit den Vorschlägen konnte ich es immer noch nicht schaffen, mich zu authentifizieren. Es stellte sich heraus, dass ich einen abschließenden '/' in meinem relativen Pfad benötigte.

d.h.

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

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X