Почему HttpClient BaseAddress не работает?

Рассмотрим следующий код, где 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 с 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 Что здесь происходит?

Ответ 1

Оказывается, из четырех возможных перестановок включения или исключения конечных или ведущих косых черт на BaseAddress и относительного URI, переданного методу GetAsync, или любого другого метода HttpClient - - работает только одна. Вы должны поместить косую черту в конце 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");
}

Несмотря на то, что я ответил на свой вопрос, я решил, что внес свой вклад в это решение, поскольку это недружелюбное поведение недокументировано. Мой коллега и я провели большую часть дня, пытаясь исправить проблему, которая была в конечном итоге вызвана этой странностью HttpClient.

Ответ 2

Ссылочное разрешение описывается Единый идентификатор ресурса RFC 3986 (URI): общий синтаксис. И именно так оно и должно работать. Чтобы сохранить базовый путь URI, вам нужно добавить косую черту в конце базового URI и удалить косую черту в начале относительного URI.

Если базовый URI содержит непустой путь, процедура слияния отбрасывает последнюю часть (после последнего /). Релевантно section:

5.2.3. Пути слияния

Псевдокод выше относится к процедуре "слияния" для слияния относительный путь с указанием пути к базовому URI. Это выполняется следующим образом:

  • Если базовый URI имеет определенный компонент полномочий и пустой   путь, затем верните строку, состоящую из "/" , объединенную с   опорный путь; в противном случае

  • возвращает строку, состоящую из компонента опорного тракта   добавляется ко всем, кроме последнего сегмента базового пути URI (то есть,   исключая любые символы после самого правого "/" в базовом URI   путь или исключить весь базовый путь URI, если он не содержит   любые символы "/" ).

Если относительный URI начинается с косой черты, он называется относительным URI абсолютного пути. В этом случае процедура слияния игнорирует весь базовый путь URI. Для получения дополнительной информации проверьте 5.2.2. Transform References.