【问题标题】:Why is HttpClient BaseAddress not working?为什么 HttpClient BaseAddress 不起作用?
【发布时间】:2014-06-19 17:52:09
【问题描述】:

考虑以下代码,其中 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 请求。但事实并非如此。

经过一番搜索,我找到了这个问题和答案: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这里发生了什么?

【问题讨论】:

  • @ГеоргийЛанец 已经提出了反向复制。我专门写了这个问题,因为另一个问题的写法不是很容易被有同样问题的人发现,我在这里写了答案,因为那里的答案遗漏了一个重要的点。
  • 但这个问题稍后再问
  • @ГеоргийЛанец 这不是它的工作原理。通常,最“规范”的问题是让重复项指向它的问题。另一个问题是关于用户遇到的单个问题,而不是像常见问题解答那样阅读。
  • @ГеоргийЛанец 另请注意,我在此问题中引用了其他问题,并解释了为什么其他问题和答案不足以解决问题。

标签: c# .net dotnet-httpclient


【解决方案1】:

事实证明,在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 的奇怪问题引起的问题。

【讨论】:

  • 谢谢。这解决了我两天来一直在努力解决的问题,在切换到 Azure、回到 IIS 和回到 IIS Express 之间,它最粗鲁地忽略了放错位置或额外的正斜杠。一旦在我的RestClient 的基类中设置,它几乎是不可见的,根本没有引起注意,而且我从未在断点等处看到完整的 url。
  • 我可以确认这个奇怪的东西(和这个修复)在 .NET Core 中仍然存在。感谢您减少我拉扯头发的蒂莫西。
  • 这是因为在构建请求时没有尾部斜杠,它会丢弃最后一部分。所以它命中something.com/resource/7。如果您将基地址设置为something/com(无论是否带有斜杠),那么是否在 api/resource/7 的开头放置斜杠也无关紧要。没有尾部斜杠,基地址的最后一部分被视为文件并在构建请求时被丢弃。
  • 只是一个可怕的实现。他们为什么不解决这个问题?
  • 确实是不寻常和古怪的。您应该在基地址上不允许斜杠,在路径上不允许前导斜杠,因为根据标准,路径始终带有斜杠。
【解决方案2】:

参考分辨率由RFC 3986 Uniform Resource Identifier (URI): Generic Syntax 描述。这正是它应该如何工作的。要保留基本 URI 路径,您需要在基本 URI 的末尾添加斜杠,并在相对 URI 的开头删除斜杠。

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

5.2.3。合并路径

上面的伪代码指的是一个“合并”例程,用于合并一个 具有基本 URI 路径的相对路径引用。这是 完成如下:

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

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

【讨论】:

  • 很好,但是像 HttpClient 这样的客户端库应该可以保护我们免受这样深奥的实现细节的影响。
  • 如果答案涵盖了为什么某些东西以这种方式工作的原因,以及相关的链接和引用,那就太好了。即使这不能直接解决问题中的问题,它也有很大帮助。
  • 这就是为什么你有 10k 星,我有 174 银
【解决方案3】:

如果您使用的是 httpClient.SendAsync(),则不会像 Get 或其他动词特定方法的重载那样提供相对 Uris 的字符串重载。

但是您可以通过将 UriKind.Relative 作为第二个参数来创建相对 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();

【讨论】:

    【解决方案4】:

    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 的利弊,但对我来说这完美无缺。希望这对某人有所帮助。

    【讨论】:

      【解决方案5】:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-03-23
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多