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

我期望它对http://something.com/api/resource/7执行GET请求。但事实并非如此。

经过一番搜索,我找到了这个问题和答案:带有BaseAddress的HttpClient。建议将/放在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这里发生了什么?

163808 次浏览

事实证明,在包含或排除BaseAddress和传递给GetAsync方法(或HttpClient的任何其他方法)的相对URI的尾斜杠或前导斜杠的四种可能排列中,只有一个排列有效。你必须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这个奇怪的问题。

引用解析由统一资源标识符(URI):通用语法描述。而这正是它应有的运作方式。为了保留基本URI路径,您需要在基本URI的末尾添加斜杠,并在相对URI的开头删除斜杠。

如果基URI包含非空路径,合并过程将丢弃其最后一部分(在last /之后)。相关部分:

5.2.3. 合并路径

上面的伪代码指的是“merge”;合并 使用基本URI路径的相对路径引用。这是 完成如下:

  • 如果基URI有一个已定义的权限组件和一个空的 路径,然后返回一个包含"/"与 参考的路径;否则李< / >
  • 返回由引用的路径组件组成的字符串 附加到除了基URI路径的最后一段之外的所有部分(即, 不包括最右边的"/"在基URI中 路径,或排除整个基本URI路径,如果它不包含 任何“/”;李字符)。< / >

如果相对URI以斜杠开头,则称为绝对路径相对URI。在这种情况下,合并过程忽略所有基本URI路径。有关更多信息,请查看5.2.2. 变换的引用部分。

遇到了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
});

我在BaseAddress中也遇到了同样的问题。我决定不使用BaseAddress,最简单的解决方案是一个简单的一行程序:

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

然后你的代码会变成:

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

我没有调查过使用BaseAddress的利弊,但对我来说,这是完美无缺的。希望这能帮助到一些人。

如果你正在使用httpClient.非同步(),就没有字符串重载来提供相对uri,就像Get或其他特定于动词的方法那样。

但是你可以用UriKind。相对作为第二个参数来创建相对Uri

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