首页 / 教程列表 / Flurl中文文档(使用教程) / Flurl流畅的URL构建方式

Flurl流畅的URL构建方式

3924 更新于: 2021-03-13 读完约需 6 分钟

流畅的URL构建方式

例子是解释流畅的Flurl URL生成器的最好方式

按照国际惯例:”Talk is cheap. Show me the code.”,首先使用代码示例来演示Flurl性感,流畅的URL生成器语法,如下:

using Flurl;

var url = "http://www.some-api.com"
    .AppendPathSegment("endpoint")
    .SetQueryParams(new {
        api_key = _config.GetValue<string>["SomeApiKey"],
        max_results = 20,
        q = "Don't worry, I'll get encoded!"
    })
    .SetFragment("after-hash");

上面的示例(以及本网站上的大多数示例)使用String的扩展方法隐式创建Url对象。如果您愿意,也可以使用Flurl内置的Url实例显式构建类似的Url对象,如:

var url = new Url("http://www.some-api.com")
    .AppendPathSegment("endpoint")
    .SetQueryParams(new {
        api_key = _config.GetValue<string>["SomeApiKey"],
        max_results = 20,
        q = "Don't worry, I'll get encoded!"
    })
    .SetFragment("after-hash");

从Flurl 3.0开始,String上可用的所有扩展方法都可以在System.Uri上使用。在这两种情况下,您都可以使用构建器方法并在单个链式调用链中使用ToString()ToUri())相互转换。

除了上面的对象表示法,SetQueryParams还接受键值对、元组或字典对象的任何集合。这些替代方案对于不是有效的c#标识符的参数名特别有用。如果你想一个一个地设置参数,还可以使用SetQueryParam(单数)方法。

需要注意的是,这些方法会覆盖之前设置的同名值,但是如果你需要保持多个同名值的参数,可以通过传递一个集合来设置多个同名值,如下:

var url = "http://www.mysite.com".SetQueryParam("x", new[] { 1, 2, 3 });
Assert.AreEqual("http://www.mysite.com?x=1&x=2&x=3", url)

在Flurl中,构建器方法及其重载是高度显式的、直观的,并且总是链式的,一些破坏性的方法如:RemoveQueryParam, RemovePathSegmentResetToRoot也包含在内。

URL解析(Parsing)

除了构建URL, Flurl还可以有效地解析现有的URL,如下:

var url = new Url("https://user:pass@www.mysite.com:1234/with/path?x=1&y=2#foo");
Assert.AreEqual("https", url.Scheme);
Assert.AreEqual("user:pass", url.UserInfo);
Assert.AreEqual("www.mysite.com", url.Host);
Assert.AreEqual(1234, url.Port);
Assert.AreEqual("user:pass@www.mysite.com:1234", url.Authority);
Assert.AreEqual("https://user:pass@www.mysite.com:1234", url.Root);
Assert.AreEqual("/with/path", url.Path);
Assert.AreEqual("x=1&y=2", url.Query);
Assert.AreEqual("foo", url.Fragment);

虽然这些解析功能类似于C#内置的URL解析功能,但Flurl的目标是与RFC 3986更加兼容,并且更符合的实际字符串应用场景,因此有以下方面的不同之处:

  • Uri.Query方法包含?字符,而Url.Query方法不包含;
  • Uri.Fragment方法包含#字符,而Url.Fragment方法不包含;
  • Uri.AbsolutePath方法总是包含一个开头字符/,而Url.Path只有在它实际存在于原始字符串中时才会包含它,比如在http://foo.com这个URL地址中,Url.Path方法返回的是一个空字符串;
  • Uri.Authority方法不包含用户信息(比如user:pass@);而Url.Authority则会包含获取到的用户信息;
  • Uri.Port方法在未指定端口时会返回默认的端口值,而Url.Port方法在未指定端口时为nullable
  • Uri不会尝试解析一个相对URL地址,而在Url的类中,假设Url字符串不是以{scheme}://开头,那么它将以一个路径开始并相应地解析它。

Url.QueryParams是一种维护了参数顺序的特殊集合类型,它允许重复名称,但针对典型的惟一名称情况进行了优化,如下:

var url = new Url("https://www.mysite.com?x=1&y=2&y=3");
Assert.AreEqual("1", url.QueryParams.FirstOrDefault("x"));
Assert.AreEqual(new[] { "2", "3" }, url.QueryParams.GetAll("y"));

可变性(Mutability)

一个Url实际上是一个可变的生成器对象,它隐式地转换为字符串。如果您需要一个不可变的URL,例如将基URL作为类的成员变量,常见的模式是将其作为字符串输入,如:

public class MyServiceClass
{
    private readonly string _baseUrl;

    public Task CallServiceAsync(string endpoint, object data) {
        return _baseUrl
            .AppendPathSegment(endpoint)
            .PostAsync(data); // 请引用Flurl.Http命名空间
    }
}

这里调用AppendPathSegment方法创建了一个新的Url对象。结果是_baseUrl没有被修改,与将其声明为Url相比,也没有添加额外的信息。

当然,你还可以使用Clone()方法来解决可变性的问题,如:

var url2 = url1.Clone().AppendPathSegment("next");

在这里,使用Clone()方法复制并获得了基于另一个Url对象的新Url对象,因此可以在不改变原始Url的情况下对复制的Url进行修改。

编码(Encoding)

Flurl负责对url中的字符进行编码,但对路径段(path segment)采用的方法与对查询字符串值采用的方法不同。假设查询字符串值是高度可变的(例如来自用户输入),而路径段往往更“固定”(可能已经编码了),在这种情况下,您不想进行双重编码。以下是Flurl遵循的规则:

  • 查询字符串值是完全url编码的;
  • 对于路径段,像/%这样的保留字符不进行编码;
  • 对于路径段,会对非法字符(如空格)进行编码;
  • 对于路径段,?字符被编码,因为查询字符串会进行特殊处理。

在某些情况下,你可能希望设置一个知道已经编码的查询参数。SetQueryParam有一个可选的isEncoded参数,如下:

url.SetQueryParam("x", "don%27t%20touch%20me", true);

虽然空格字符的官方URL编码是%20,但在查询参数中使用字符+是很常见的。你可以通过Url.ToString()的可选参数encodeSpaceAsPlus来指定是否将空格编码成+号,示例如下:

var url = "http://foo.com".SetQueryParam("x", "hi there");
Assert.AreEqual("http://foo.com?x=hi%20there", url.ToString());
Assert.AreEqual("http://foo.com?x=hi+there", url.ToString(true));

一些实用的方法

Url还包含一些方便的静态方法,例如Combine,它是一个用来组合URL地址地类似C#文件系统中的Path.Combine方法URL地址,确保各部分之间只有一个分隔符,如:

var url = Url.Combine(
    "http://foo.com/",
    "/too/", "/many/", "/slashes/",
    "too", "few?",
    "x=1", "y=2"
// 结果为: "http://www.foo.com/too/many/slashes/too/few?x=1&y=2"

其他一些关于编码/解码的帮助方法:

Url.Encode(string s, bool encodeSpaceAsPlus);
Url.EncodeIllegalCharacters(string s, bool encodeSpaceAsPlus);
Url.Decode(string s, bool interpretPlusAsSpace);

版权声明:本作品系原创,版权归码友网所有,如未经许可,禁止任何形式转载,违者必究。

发表评论

登录用户才能发表评论, 请 登 录 或者 注册