Go 内置的 net/url 包提供了用于 URL 解析、构建和查询的功能。这个包使我们能够处理 URL,从中提取出各个部分,比如协议、主机、路径和查询参数等。
https://pkg.go.dev/net/url
简介
格式
1 2 3
| <schema>://<user>:<password>@<host>:<port>/<path>:<params>?<query> 或者 <scheme>:<opaque>[?<query>][#<fragment>]
|
scheme: 方案是如何访问指定资源的主要标识符,他会告诉负责解析URL应用程序应该使用什么协议。
host: 主机组件标识了因特网上能够访问资源的宿主机器,可以有主机名或者是IP地址来表示。
port: 端口标识了服务器正在监听的网络端口。默认端口号是80。
path: URL的路径组件说明了资源位于服务器的什么地方。
params: URL中通过协议参数来访问资源,比名值对列表,分号分割来进行访问。
query: 字符串是通过提问问题或进行查询来缩小请求资源类的范围。frag: 为了引用部分资源或资源的一个片段,比如URL指定HTML文档中一个图片或一个小节。HTTP通常只处理整个对象,而不是对象的片段,客户端不能将片段传送给服务器。浏览器从服务器获取整个资源之后,会根据片段来显示你感兴趣的片段部分。
概览
URL 结构体定义
1 2 3 4 5 6 7 8 9 10 11 12 13
| type URL struct { Scheme string Opaque string User *Userinfo Host string Path string RawPath string OmitHost bool ForceQuery bool RawQuery string Fragment string RawFragment string }
|
一些常用的方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| func QueryEscape(s string) string ueryEscape 函数对 s 进行转码使之可以安全的用在 URL 查询里。
func QueryUnescape(s string) (string, error) QueryUnescape 函数用于将 QueryEscape 转码的字符串还原。它会把 %AB 改为字节 0xAB,将'+' 改为' '。如果有某个 % 后面未跟两个十六进制数字,本函数会返回错误。
type Error struct { Op string URL string Err error } Error 会报告一个错误,以及导致该错误发生的 URL 和操作。 func (e *Error) Error() string
type EscapeError string func (e EscapeError) Error() string
type URL struct {} URL 类型代表一个解析后的 URL(或者说,一个 URL 参照)。URL 基本格式如下:
func Parse(rawurl string) (url *URL, err error) Parse 函数解析 rawurl 为一个 URL 结构体,rawurl 可以是绝对地址,也可以是相对地址。 func ParseRequestURI(rawurl string) (url *URL, err error) ParseRequestURI 函数解析 rawurl 为一个 URL 结构体,本函数会假设 rawurl 是在一个 HTTP 请求里,因此会假设该参数是一个绝对 URL 或者绝对路径,并会假设该 URL 没有#fragment 后缀。(网页浏览器会在去掉该后缀后才将网址发送到网页服务器) func (u *URL) IsAbs() bool 判断是否是绝对路径func (*URL) IsAbs,在 URL 是绝对 URL 时才返回真。 func (u *URL) Query() Values 解析 RawQuery 字段并返回其表示的 Values 类型键值对。 func (u *URL) RequestURI() string 返回编码好的 path?query 或 opaque?query 字符串,用在 HTTP 请求里。 func (u *URL) String() string 将 URL 重构为一个合法 URL 字符串。 func (u *URL) Parse(ref string) (*URL, error) 以 u 为上下文来解析一个 URL,ref 可以是绝对或相对 URL。本方法解析失败会返回 nil, err;否则返回结果和 ResolveReference 一致。 func (u *URL) ResolveReference(ref *URL) *URL 根据一个绝对 URI 将一个 URI 补全为一个绝对 URI,参见 RFC 3986 节 5.2。参数 ref 可以是绝对 URI 或者相对 URI。ResolveReference 总是返回一个新的 URL 实例,即使该实例和 u 或者 ref 完全一样。如果 ref 是绝对 URI,本方法会忽略参照 URI 并返回 ref 的一个拷贝。
type Userinfo struct {
func User(username string) *Userinfo User 函数返回一个用户名设置为 username 的不设置密码的 *Userinfo。 func UserPassword(username, password string) *Userinfo UserPassword 函数返回一个用户名设置为 username、密码设置为 password 的 *Userinfo。这个函数应该只用于老式的站点,因为风险很大,不建议使用,参见 RFC 2396。 func (u *Userinfo) Username() string Username 方法返回用户名。 func (u *Userinfo) Password() (string, bool) 如果设置了密码返回密码和真,否则会返回假。 func (u *Userinfo) String() string String 方法返回编码后的用户信息,格式为 "username[:password]"。
type Values map[string][]string Values 将建映射到值的列表。它一般用于查询的参数和表单的属性。不同于 http.Header 这个字典类型,Values 的键是大小写敏感的。 func ParseQuery(query string) (m Values, err error) ParseQuery 函数解析一个 URL 编码的查询字符串,并返回可以表示该查询的 Values 类型的字典。本函数总是返回一个包含了所有合法查询参数的非 nil 字典,err 用来描述解码时遇到的(如果有)第一个错误。 func (v Values) Get(key string) string Get 会获取 key 对应的值集的第一个值。如果没有对应 key 的值集会返回空字符串。获取值集请直接用 map。 func (v Values) Set(key, value string) Set 方法将 key 对应的值集设为只有 value,它会替换掉已有的值集。 func (v Values) Add(key, value string) Add 将 value 添加到 key 关联的值集里原有的值的后面。 func (v Values) Del(key string) Del 删除 key 关联的值集。 func (v Values) Encode() string Encode 方法将 v 编码为 url 编码格式 ("bar=baz&foo=quux"),编码时会以键进行排序。
|
示例
解析普通 URL
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| package main import ( "fmt" "net/url" ) func main() { rawURL := "https://www.example.com/path?query=123#fragment" parsedURL, err := url.Parse(rawURL) if err != nil { fmt.Println("Error parsing URL:", err) return } fmt.Println("Scheme:", parsedURL.Scheme) fmt.Println("Host:", parsedURL.Host) fmt.Println("Path:", parsedURL.Path) fmt.Println("RawQuery:", parsedURL.RawQuery) fmt.Println("Fragment:", parsedURL.Fragment) }
|
再来一个
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| s:="mysql+pymysql://base:xxxx.mysql.rds.aliyuncs.com:3306/dbtest?charset=utf8&test=test#12345" u,err:=url.Parse(s) if err!=nil{ panic(err) } fmt.Println(reflect.TypeOf(u))
fmt.Println(u.Opaque) fmt.Println(u.ForceQuery)
fmt.Println(u.User) fmt.Println(u.User.String()) fmt.Println(u.User.Username()) fmt.Println(u.User.Password())
fmt.Println(u.Scheme)
fmt.Println(u.Path) fmt.Println(u.Fragment) fmt.Println(u.RawPath)
fmt.Println(u.Host) fmt.Println(u.RawQuery)
|
解析查询字符串
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| package main import ( "fmt" "net/url" ) func main() { queryString := "name=John&age=30&city=New+York" queryParams, err := url.ParseQuery(queryString) if err != nil { fmt.Println("Error parsing query string:", err) return } fmt.Println("Name:", queryParams.Get("name")) fmt.Println("Age:", queryParams.Get("age")) fmt.Println("City:", queryParams.Get("city")) for key, values := range queryParams { fmt.Println(key, ":", values) } }
|
构造 URL
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| package main import ( "fmt" "net/url" ) func main() { scheme := "https" host := "www.example.com" path := "/path" query := url.Values{} query.Add("query", "123") fragment := "fragment" rawURL := fmt.Sprintf("%s://%s%s?%s#%s", scheme, host, path, query.Encode(), fragment) fmt.Println("Constructed URL:", rawURL) }
|
注意事项
URL 编码:在处理 URL 时,特别是查询字符串中的参数值,需要注意 URL 编码。net/url
包提供了 url.QueryEscape
和 url.QueryUnescape
函数来对字符串进行编码和解码。
错误处理:在解析 URL 或查询字符串时,可能会出现错误(如格式不正确等),需要检查返回的错误并进行适当的处理。