url 包

介绍

该包提供 url 数据解析功能。

主要接口

class URL

public class URL <: ToString

该类提供接口解析 URL,其中的 % 编码会被解码,保存在相应的组件之中,而初始值保存在相应的 raw 属性之中。(暂时不支持 IPv6 主机形式的 URL 解析,暂时未提供各组件的编解码功能。)URL 中的用户名和密码部分(如果存在的话)也会按照 rfc3986 协议的说明被解析,但是该协议也明确说明了,在任何场景下,明文保存用户信息都有被泄露的风险,所以我们不建议您在 URL 中明文保存用户信息,这不安全!

init

public init(scheme!: String, hostName!: String, path!: String)

功能:构造一个 URL 实例。

参数:

  • scheme:协议
  • hostName:不包含端口号的主机名
  • path:路径

异常:

  • 异常 UrlSyntaxException: 当出现以下任何情况之一时,会抛出异常。
    1. 在没有协议 scheme 的情况下,拥有主机名 hostName
    2. 只有协议 scheme
    3. 存在协议和路径的情况下,路径 path 不是绝对路径
    4. 存在非法字符

prop scheme

public prop scheme: String

功能:获取 URL 中协议部分,用字符串表示。

prop opaque

public prop opaque: String

功能:获取 URL 中不透明部分,用字符串表示。

prop userInfo

public prop userInfo: UserInfo

功能:获取解码后的用户名和密码信息,用 UserInfo 实例表示。

prop rawUserInfo

public prop rawUserInfo: UserInfo

功能:获取解码前的用户名和密码信息,用 UserInfo 实例表示。

prop hostName

public prop hostName: String

功能:获取解码后的主机名,用字符串表示。

prop port

public prop port: String

功能:获取端口号,用字符串表示,空字符串表示无端口号。

prop path

public prop path: String

功能:获取解码后路径,用字符串表示。

prop rawPath

public prop rawPath: String

功能:获取解码前路径,用字符串表示。

prop query

public prop query: ?String

功能:获取解码后查询组件,用字符串表示。

prop rawQuery

public prop rawQuery: ?String

功能:获取解码前查询组件,用字符串表示。

prop fragment

public prop fragment: ?String

功能:获取解码后锚点组件,用字符串表示。

prop rawFragment

public prop rawFragment: ?String

功能:获取解码前锚点组件,用字符串表示。

prop queryForm

public prop queryForm: Form

功能:获取解码后查询组件,用 Form 实例表示。

func parse

public static func parse(rawUrl: String): URL

功能:将原始字符串解析成 URL 对象,相对路径或绝对路径均可。该函数可以解析 url 中的用户名和密码(如果内部存在的话),这是符合 rfc3986 协议的解析功能,但是该协议也明确说明了,在任何场景下,明文保存用户信息都有被泄露的风险,所以我们不建议您在 url 中明文保存用户信息,这不安全!

参数:

  • rawUrl:URL 字符串

返回值:解析字符串得到的 URL 实例

异常:

  • 异常 UrlSyntaxException:当 URL 字符串中包含非法字符时,抛出异常
  • 异常 IllegalArgumentException:当被编码的字符不符合 UTF-8 的字节序列规则时,抛出异常

func isAbsoluteURL

public func isAbsoluteURL(): Bool

功能:判断 url 是否为绝对 URL,scheme 存在时,URL 是绝对 URL。

返回值:是否为绝对 URL

func resolveURL

public func resolveURL(ref: URL): URL

功能:以当前 URL 实例为基础 URL,以传入的 URL 为参考 URL,根据协议生成一个新的 URL 实例。

例如:http://a/b/c/d;p?q 为基础 URL,以下 = 左边为参考 URL,右边为生成的新 URL:

更详细行为,参见 rfc3986。

参数:

  • ref:参考 URL 对象

返回值:新的 URL 实例

func mergePaths

public static func mergePaths(basePath: String, refPath: String): String

功能:合并有效的两个路径,并消除合并后的 path 中的"."字符,".."字符,将多个连续的"/"替换为单个"/",例如:

  • "/a/b/c" 合并 "/d" 输出 "/d"
  • "/a/b/c" 合并 "d" 输出 "/a/b/d"
  • "/a/b/" 合并 "d/e/../f" 输出 "/a/b/d/f"
  • "/a/b/c/" 合并 "./../../g" 输出 "/a/g"

参数:

  • basePath:基础路径
  • refPath:引用路径

返回值:合并且标准化后的路径

func toString

public func toString(): String

功能:获取当前 URL 实例的字符串值。

返回值:当前 URL 实例的字符串值

func replace

public func replace(scheme!: Option<String> = None, userInfo!: Option<String> = None,
 hostName!: Option<String> = None, port!: Option<String> = None, path!: Option<String> = None, 
 query!: Option<String> = None, fragment!: Option<String> = None): URL

功能:替换 URL 对象的各组件,并且返回一个新的 URL 对象。 参数:

  • scheme:方案部分
  • userInfo:用户信息
  • hostName:主机名
  • port:端口号
  • path:路径
  • query:查询部分
  • fragment:锚点部分

返回值:新的 URL 对象

异常:

  • 异常 UrlSyntaxException: 当出现以下任何情况之一时,会抛出异常。
    1. 方案 scheme 为空而主机名不为空时。
    2. 主机名为空而用户信息或端口号不为空时。
    3. 方案 scheme 不为空而主机名和路径同时为空时。
    4. 方案 scheme 不为空而路径不是绝对路径时。
    5. 任意组件不合法时。

class UserInfo

public class UserInfo <: ToString {
    public init()
    public init(userName: String)
    public init(userName: String, passWord: String)
    public init(userName: String, passWord: Option<String>)
}

UserInfo 表示 url 中用户名和密码信息, URL.parse 可以解析 url 中的用户名和密码,这是符合 rfc3986 协议的解析功能,但是该协议也明确说明了,在任何场景下,明文保存用户信息都有被泄露的风险,所以我们不建议您在 url 中明文保存用户信息,这不安全!

init

public init()

功能:创建 UserInfo 实例。

init

public init(userName: String)

功能:根据用户名创建 UserInfo 实例。 参数:

  • userName:用户名

init

public init(userName: String, passWord: String)

功能:根据用户名和密码创建 UserInfo 实例。 参数:

  • userName:用户名
  • passWord:密码

init

public init(userName: String, passWord: Option<String>)

功能:根据用户名和 Option 类型的密码创建 UserInfo 实例。 参数:

  • userName:用户名
  • passWord:密码,用 Option 类型表示

func toString

public func toString(): String

功能:将当前 UserInfo 实例转换为字符串。

返回值:当前 UserInfo 示例的字符串表示

func password

public func password(): Option<String>

功能:获取密码信息(不建议在 url 中明文保存用户信息!详情参上!)。

返回值:将密码以 Option 形式返回

func username

public func username(): String

功能:获取用户名信息。

返回值:字符串类型返回用户名

class Form

public class Form {
    public init()
    public init(queryComponent: String)
}

Form 以 key-value 键值对形式存储 http 请求的参数, 同一个 key 可以对应多个 value, value 以数组形式存储。

init

public init()

功能:构造一个默认的 Form 实例。

init

public init(queryComponent: String)

功能:根据 URL 编码的查询字符串,即 URL 实例的 query 部分构造 Form 实例,解析 URL 编码的查询字符串,得到若干键值对,并将其添加到新构造的 Form 实例中。 参数:

  • queryCompoent:'&' 符号分隔多个键值对;'=' 分隔的左侧作为 key 值,右侧作为 value 值(没有 '=' 或者 value 为空,均是允许的)

异常:

  • 异常 UrlSyntaxException:当 URL 字符串中包含非法转义字符时,抛出异常

func isEmpty

public func isEmpty(): Bool

功能:判断 Form 是否为空。

返回值:如果为空,则返回 true;否则,返回 false

func get

public func get(key: String): Option<String>

功能:根据 key 获取第一个关联的 value。

参数:

  • key:指定键

返回值:根据指定键获取的第一个值,用 Option 类型表示

func getAll

public func getAll(key: String): ArrayList<String>

功能:根据 key - 获取所有关联的 value。

参数:

  • key:根据该键获取值

返回值:根据指定键获取的全部值

func set

public func set(key: String, value: String): Unit

功能:重置指定 key 对应的 value。

参数:

  • key:指定键
  • value:将指定键的值设置为 value

func add

public func add(key: String, value: String): Unit

功能:新增 key-value 映射, 如果 key 已存在,则将 value 添加到原来 value 数组的最后面。

参数:

  • key:指定键,可以是新增的
  • value:将该值添加到指定键对应的值数组中

func remove

public func remove(key: String): Unit

功能:删除 key 及其对应 value。

参数:

  • key:删除的键

func clone

public func clone(): Form

功能:克隆 Form。

返回值:克隆得到的新 Form 实例

func toEncodeString

public func toEncodeString(): String

功能:对表单中的键值对进行编码。未保留字符 unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" 不会被编码,空格将编码为 '+'。

返回值:编码后的字符串

class UrlSyntaxException

public class UrlSyntaxException <: Exception {
    public init(reason: String)
    public init(input: String, reason: String)
}

url 解析异常类

init

public init(reason: String)

功能:根据错误原因构造 UrlSyntaxException 实例。

参数:

  • reason:解析错误的原因

init

public init(input: String, reason: String)

功能:根据 url 及错误原因构造 UrlSyntaxException 实例,其内部的 message 整合了 url 和错误原因。

参数:

  • input:原生 url 或其片段
  • reason:解析错误的原因

示例

parse 的使用

使用 parse 函数解析 URL 字符串,生成 URL 对象。

代码如下:

from encoding import url.*

main(): Int64 {
    var url = URL.parse("http://www.example.com:80/path%E4%BB%93%E9%A2%89?key=value%E4%BB%93%E9%A2%89#%E4%BD%A0%E5%A5%BD")
    println("url.scheme = ${url.scheme}")
    println("url.opaque = ${url.opaque}")
    println("url.userInfo = ${url.userInfo}")
    println("url.rawUserInfo = ${url.rawUserInfo}")
    println("url.hostName = ${url.hostName}")
    println("url.port = ${url.port}")
    println("url.path = ${url.path}")
    println("url.rawPath = ${url.rawPath}")
    println("url.query = ${url.query.getOrThrow()}")
    println("url.rawQuery = ${url.rawQuery.getOrThrow()}")
    println("url.fragment = ${url.fragment.getOrThrow()}")
    println("url.rawfragment = ${url.rawFragment.getOrThrow()}")
    println("url = ${url}")
    return 0
}

运行结果形如下:

url.scheme = http
url.opaque =
url.userInfo =
url.rawUserInfo =
url.hostName = www.example.com
url.port = 80
url.path = /path仓颉
url.rawPath = /path%E4%BB%93%E9%A2%89
url.query = key=value仓颉
url.rawQuery = key=value%E4%BB%93%E9%A2%89
url.fragment = 你好
url.rawfragment = %E4%BD%A0%E5%A5%BD
url = http://www.example.com:80/path%E4%BB%93%E9%A2%89?key=value%E4%BB%93%E9%A2%89#%E4%BD%A0%E5%A5%BD

Form 的构造使用 1

创建 Form 类,并通过 get 获取 key 对应映射的 value。

代码如下:

from encoding import url.*

main(): Int64 {
    var s = Form("1=2&2=3&1=2&&")
    print(s.get("1").getOrThrow())
    return 0
}

运行结果如下:

2

Form 的构造使用 2

创建 Form 正则类,并通过 get 获取 key 对应映射的 value。

代码如下:

from encoding import url.*

main(): Int64 {
   var s = Form("2=3&1=%6AD&1=2")
   // 对于 %6A 解码成 j,重复的 key 调用 get 获取第一个 value 值 jD
   print(s.get("1").getOrThrow())
   return 0
}

运行结果如下:

jD

Form 的构造使用 3

分别调用 add,set,clone,打印输出前后变化。

代码如下:

from encoding import url.*

main(): Int64 {
    var f = Form()
    f.add("k", "v1")
    f.add("k", "v2")
    println(f.get("k").getOrThrow())
    f.set("k", "v")
    println(f.get("k").getOrThrow())
    let clone_f = f.clone()
    clone_f.add("k1", "v1")
    println(clone_f.get("k1").getOrThrow())
    println(f.get("k1") ?? "kkk")
    0
}

运行结果如下:

v1
v
v1
kkk