为什么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。但事实并非如此。

经过一番搜索,我找到了这个问题和答案:具有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这是怎么回事?



@ГеоргийЛанец已经提出反向重复。我之所以写这个问题,是因为其他问题的写法不是同样问题的人都可以发现的,我之所以在这里写下答案,是因为那里的答案没有重点。
蒂莫西·希尔兹

但是稍后会问这个问题
George Lanetz 2015年

2
@ГеоргийЛанец这不是它的工作原理。通常,最“规范”的问题是使指向该问题的重复项的问题。另一个问题是用户遇到的一个单一问题,而不是像FAQ那样阅读。
蒂莫西·希尔兹

2
@ГеоргийЛанец同时请注意,我引用了该问题中的另一个问题,并解释了为什么另一个问题和答案不足以解决问题。
蒂莫西·希尔兹

Answers:


719

事实证明,在四种可能的排列方式中,包括或排除BaseAddress传递给GetAsync方法的URI和相对URI的尾随或前导斜线以及传递给该方法(或任何其他方法)的相对URI 中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


4
谢谢。这解决了我在两天的大部分时间里一直在苦苦挣扎的问题,在切换到Azure,回到IIS和回到IIS Express之间,这最不礼貌地忽略了放错位置或多余的正斜杠。一旦在基类我的设置RestClient,这是几乎看不见,但无人注意的一切,我从来没有看到完整的URL我的断点等
ProfK

43
我可以确认这种怪异(和此修复程序)在.NET Core中仍然有用。感谢您减少我的提摩西头发。
Nate Barbettini

8
这是因为在生成请求时不加任何斜杠,它会丢弃最后一部分。因此它命中了something.com/resource/7。如果您将基址设置为something / com(是否带斜杠也没关系),则将斜杠放在api / resource / 7的开头也没关系。没有尾部斜杠时,基地址的最后部分被视为文件,并在建立请求时删除。
霹雳霹雳州

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

6
只是一个可怕的实现。他们为什么不解决这个问题?
timmkrause

55

参考解析由RFC 3986统一资源标识符(URI):通用语法描述。这正是它应该如何工作的。要保留基本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。将整个网址放在GetAsync()中


33
不会回答任何问题。
阿奇博尔德

7
BaseAddress降低了噪声。无论如何对我来说。:)
MetalMikester

2
我将不同意负面评论。我花了两天的时间来弄清楚为什么我的HttpClient调用可以在我的Dev PC上运行但在服务器上中断的原因。奇怪的是Powershell可以工作,但是.net不能。我正在使用.SendAsyc。然后我发现.GetAsyc有效。这使我走了一条不同的路,最终到了这里。在基址和相对URL之间添加或删除/并没有任何作用。仍然出现404错误...。但是,当我没有设置基本地址并将整个路径放入相对地址时,它就起作用了!同样,这是与.SendAsync一起使用的,但是有2天我永远都不会回来!
da_jokker
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.