流畅的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
, RemovePathSegment
和ResetToRoot
也包含在内。
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);
发表评论
登录用户才能发表评论, 请 登 录 或者 注册