使用可能有或没有尾随 / 的 Uri 字符串

Using Uri strings that may or may not have trailing /'s

我在代码中使用 HttpClient 有一段时间了,一直觉得它对 Uris 的使用导致我的实现有些脆弱。我们的大部分服务端点基地址都在 app./web.config 中。因此,它们可以很容易地更改。

我发现当使用这些端点字符串生成 Uri 时,如果它们不以 / 结尾,我的行为就会变得非常古怪。使用非 / 终止的 BaseAddress 调用 GetAsync() 时,发送 GET 请求的结果串联 URL 通常会在最终 [=13= 之后丢弃字符串] 在 BaseAddress 中,否则它将删除 GetUri 中第一个 / 之前的字符串。

例如:

BaseAddress: http://test/serviceEndpoint

GetUri: api/customer

当使用 GetUri 调用 HttpClient.GetAsync() 时,它将尝试从 http://test/api/customer 获取 GET。如果我用 / 来限制 BaseAddress,一切都会按预期进行。

我的问题BaseAddress 是配置驱动的,在 .config 文件中添加注释说 "Make sure you end all Service URLs with a /!" 是一个非常脆弱的解决方案.

所以我养成了在所有 HttpClient 构造中使用以下代码的习惯:

        var service = settings.GetValue("ServiceBaseUrl");
        var serviceUri = !service.EndsWith("/")
            ? new Uri(service + "/")
            : new Uri(service);

        _client = new HttpClient
        {
            BaseAddress = serviceUri
        };`

虽然这并不脆弱,但在每个 HttpClient 构造函数中使用它感觉很重复。 HttpClientUri 中是否有我可以用来避免此样板代码的内容?

HttpClient 或 Uri 中没有任何内容可以解决这个问题,这就是为什么我在 Flurl 中以几种方式解决它的原因。 Flurl 的 AppendPathSegmentAppendPathSegments 方法将确保段之间只有一个“/”分隔符。例如,这些产生相同的结果:

"http://mysite/".AppendPathSegment("/endpoint")
"http://mysite".AppendPathSegment("endpoint")

静态 Url.Combine 方法也有这种行为,作为 URLs 的 Path.Combine

这些和其他有用的 URL 构建位在核心 Flurl package, but the real fun is in Flurl.Http 中可用,它将流畅的 URL 构建器与 HttpClient 和 Json.NET 让你可以从字符串到 URL 再到 HTTP 请求再到反序列化的结果,而无需将笔从纸上移开,可以这么说:

var result = await settings.GetValue("ServiceBaseUrl")
    .AppendPathSegment("endpoint")
    .GetJsonAsync<T>();