Go 標準庫之 net/url(查詢轉義、查詢參數增/刪/改/查、解析URL)

1. URL 概述

import "net/url"

url 包解析 URL 並實現了查詢的轉碼。URL 提供了一種定位因特網上任意資源的手段,但這些資源是可以通過各種不同的方案(比如 HTTPFTPSMTP )來訪問,因此 URL 語法會隨着方案的不同而不同。

完整的 URL 格式爲:

<schema>://<user>:<password>@<host>:<port>/<path>:<params>?<query>#<frag>

各部分字段說明:

  • scheme : 方案是如何訪問指定資源的主要標識符,他會告訴負責解析 URL 應用程序應該使用什麼協議;
  • user :用戶名;
  • password :密碼;
  • host : 主機組件標識了因特網上能夠訪問資源的宿主機器,可以有主機名或者是 IP 地址來表示;
  • port : 端口標識了服務器正在監聽的網絡端口。默認端口號是 80;
  • path : URL 的路徑組件說明了資源位於服務器的什麼地方;
  • params : URL 中通過協議參數來訪問資源,比名值對列表,分號分割來進行訪問;
  • query : 字符串是通過提問問題或進行查詢來縮小請求資源類的範圍;
  • frag : 爲了引用部分資源或資源的一個片段,比如 URL 指定 HTML 文檔中一個圖片或一個小節;

HTTP 通常只處理整個對象,而不是對象的片段,客戶端不能將片段傳送給服務器。瀏覽器從服務器獲取整個資源之後,會根據片段來顯示你感興趣的片段部分。

2. 主要類型和函數

2.1 type URL

GoURL 結構體如下:

type URL struct {
    Scheme   string    //具體指訪問服務器上的資源使用的哪種協議
    Opaque   string    // 編碼後的不透明數據
    User     *Userinfo // 用戶名和密碼信息,有些協議需要傳入明文用戶名和密碼來獲取資源,比如 FTP
    Host     string    // host或host:port,服務器地址,可以是 IP 地址,也可以是域名信息
    Path     string  //路徑,使用"/"分隔
    RawPath    string    // 已編碼的路徑提示(參見EscapedPath方法)
	ForceQuery bool      // 添加一個查詢('?'),即使RawQuery爲空
    RawQuery string // 編碼後的查詢字符串,沒有'?'
    Fragment string // 引用的片段(文檔位置),沒有'#'
}

示例代碼:

func main() {
	urlString := "https://admin:[email protected]:80/search?mq=test#12345"
	u, err := url.Parse(urlString)
	if err != nil {
		fmt.Println("parse error ", err)
	}
	fmt.Printf("u type is %T, u is %#v\n", u, u)
	/*
		u type is *url.URL,
		u is &url.URL{
			Scheme:"https", Opaque:"", User:(*url.Userinfo)(0xc000088150),
			Host:"www.baidu.com:80", Path:"/search", RawPath:"", ForceQuery:false,
			RawQuery:"mq=test", Fragment:"12345"
		}

	*/
	fmt.Printf("u.Scheme is %#v\n", u.Scheme) // u.Scheme is "https"
	fmt.Printf("u.Opaque is %#v\n", u.Opaque) // u.Opaque is ""
	fmt.Printf("u.User is %#v\n", u.User)
	// u.User is &url.Userinfo{username:"admin", password:"passwd", passwordSet:true}

	fmt.Printf("u.Host is %#v\n", u.Host)             // u.Host is "www.baidu.com:80"
	fmt.Printf("u.Path is %#v\n", u.Path)             // u.Path is "/search"
	fmt.Printf("u.RawPath is %#v\n", u.RawPath)       // u.RawPath is ""
	fmt.Printf("u.ForceQuery is %#v\n", u.ForceQuery) // u.ForceQuery is false
	fmt.Printf("u.RawQuery is %#v\n", u.RawQuery)     // u.RawQuery is "mq=test"
	fmt.Printf("u.Fragment is %#v\n", u.Fragment)     // u.Fragment is "12345"

}

2.1.1 func Parse

func Parse(rawurl string) (url *URL, err error)

Parse 函數解析rawurl爲一個URL結構體,rawurl` 可以是絕對地址,也可以是相對地址。

2.1.2 func ParseRequestURI

func ParseRequestURI(rawurl string) (url *URL, err error)

ParseRequestURI 函數解析 rawurl 爲一個 URL 結構體,本函數會假設 rawurl 是在一個 HTTP 請求裏,因此會假設該參數是一個絕對 URL 或者絕對路徑,並會假設該 URL 沒有 #fragment 後綴。(網頁瀏覽器會在去掉該後綴後纔將網址發送到網頁服務器)

func main() {
	urlString := "https://admin:[email protected]:80/search?mq=test#12345"
	u, err := url.ParseRequestURI(urlString)
	if err != nil {
		fmt.Println("parse error ", err)
	}
	fmt.Printf("u.Fragment is %#v\n", u.Fragment) // u.Fragment is ""

}

2.1.3 func (*URL) IsAbs

func (u *URL) IsAbs() bool

函數在 URL 是絕對 URL 時才返回真。

2.1.4 func (*URL) Query

func (u *URL) Query() Values

Query 方法解析 RawQuery 字段並返回其表示的 Values 類型鍵值對。

2.1.5 func (*URL) RequestURI

func (u *URL) RequestURI() string

RequestURI 方法返回編碼好的 path?queryopaque?query 字符串,用在 HTTP 請求裏。

2.1.6 func (*URL) String

func (u *URL) String() string

StringURL 重構爲一個合法 URL 字符串。

2.1.7 func (*URL) Parse

func (u *URL) Parse(ref string) (*URL, error)

Parse 方法以 u 爲上下文來解析一個 URLref 可以是絕對或相對 URL 。本方法解析失敗會返回 nil , err ;否則返回結果和 ResolveReference 一致。

func main() {
	u, _ := url.Parse("http://example.com/dir/")
	fmt.Println(u) // http://example.com/dir/

	result, _ := u.Parse("./search?mq=rabbitmq")
	fmt.Println(result) // http://example.com/dir/search?mq=rabbitmq
}

2.1.8 func (*URL) ResolveReference

func (u *URL) ResolveReference(ref *URL) *URL

本方法根據一個絕對 URI 將一個 URI 補全爲一個絕對 URI 。參數 ref 可以是絕對 URI 或者相對 URIResolveReference 總是返回一個新的 URL 實例,即使該實例和 u 或者 ref 完全一樣。如果 ref 是絕對 URI ,本方法會忽略參照 URI 並返回 ref 的一個拷貝。

2.1.9 代碼示例

func main() {
	urlString := "https://www.baidu.com/search?mq=rabbitmq&queue=people#12345"
	u, err := url.Parse(urlString)
	if err != nil {
		fmt.Println("parse error ", err)
	}
	fmt.Printf("u.IsAbs is %#v\n", u.IsAbs()) // u.IsAbs is true
	fmt.Printf("u.Query is %#v\n", u.Query())
	// u.Query is url.Values{"mq":[]string{"rabbitmq"}, "queue":[]string{"people"}}
	fmt.Printf("u.RequestURI is %#v\n", u.RequestURI())
	// u.RequestURI is "/search?mq=rabbitmq&queue=people"
	fmt.Printf("u.String is %#v\n", u.String())
	// u.String is "https://www.baidu.com/search?mq=rabbitmq&queue=people#12345"

}

2.2 type Values

type Values map[string][]string

Values 將建映射到值的列表。它一般用於查詢的參數和表單的屬性。不同於 http.Header 這個字典類型, Values 的鍵是大小寫敏感的。

2.2.1 func ParseQuery

func ParseQuery(query string) (m Values, err error)

ParseQuery 函數解析一個 URL 編碼的查詢字符串,並返回可以表示該查詢的 Values 類型的字典。本函數總是返回一個包含了所有合法查詢參數的非 nil 字典, err 用來描述解碼時遇到的(如果有)第一個錯誤。

代碼示例:

func main() {
	rawUrl := "mq=rabbitmq&queue=people"
	v, err := url.ParseQuery(rawUrl)
	if err != nil {
		fmt.Println("ParseQuery error ", err)
	}
	fmt.Printf("v type is %T, v is %#v\n", v, v)
	// v type is url.Values, v is url.Values{"mq":[]string{"rabbitmq"}, "queue":[]string{"people"}}

	// 等價於下面的方法
	urlString := "https://www.baidu.com/search?mq=rabbitmq&queue=people#12345"
	u, _ := url.Parse(urlString)
	queryV := u.Query()
	fmt.Printf("queryV type is %T, queryV is %#v\n", queryV, queryV)
	// queryV type is url.Values, queryV is url.Values{"mq":[]string{"rabbitmq"}, "queue":[]string{"people"}}
}

2.2.2 func (Values) Get

func (v Values) Get(key string) string

Get 會獲取 key 對應的值集的第一個值。如果沒有對應 key 的值集會返回空字符串。獲取值集請直接用 map

2.2.3 func (Values) Set

func (v Values) Set(key, value string)

Set 方法將 key 對應的值集設爲只有 value ,它會替換掉已有的值集。

2.2.4 func (Values) Add

func (v Values) Add(key, value string)

Addvalue 添加到 key 關聯的值集裏原有的值的後面。

2.2.5 func (Values) Del

func (v Values) Del(key string)

Del 刪除 key 關聯的值集。

2.2.6 func (Values) Encode

func (v Values) Encode() string

Encode 方法將 v 編碼爲 ur 編碼格式(“bar=baz&foo=quux”),編碼時會以鍵進行排序。

2.2.7 代碼示例

func main() {
	rawUrl := "mq=rabbitmq&queue=people"
	v, err := url.ParseQuery(rawUrl)
	if err != nil {
		fmt.Println("ParseQuery error ", err)
	}
	fmt.Printf("v type is %T, v is %#v\n", v, v)
	// v type is url.Values, v is url.Values{"mq":[]string{"rabbitmq"}, "queue":[]string{"people"}}

	fmt.Println(v.Get("mq")) // rabbitmq
	v.Set("mq", "redis")
	fmt.Println(v.Get("mq")) // redis
	v.Add("name", "wohu")
	fmt.Printf("v is %#v\n", v)
	// v is url.Values{"mq":[]string{"redis"}, "name":[]string{"wohu"}, "queue":[]string{"people"}}

	fmt.Printf("v.Encode is %#v\n", v.Encode()) // v.Encode is "mq=redis&name=wohu&queue=people"
	v.Del("name")
	fmt.Printf("v is %#v\n", v)
	// v is url.Values{"mq":[]string{"redis"}, "queue":[]string{"people"}}
}

2.3 查詢轉義

2.3.1 func QueryEscape

func QueryEscape(s string) string

QueryEscape 函數對 s 進行轉碼使之可以安全的用在 URL 查詢裏。

2.3.2 func QueryUnescape

func QueryUnescape(s string) (string, error)

QueryUnescape 函數用於將 QueryEscape 轉碼的字符串還原。它會把 %AB 改爲字節 0xAB ,將 + 改爲空格 。如果有某個 % 後面未跟兩個十六進制數字,本函數會返回錯誤。

2.3.3 代碼示例

func main() {
	rawUrl := "mq=rabbitmq&queue=people"
	stdUrl := url.QueryEscape(rawUrl)
	fmt.Printf("stdUrl is %v\n", stdUrl) // stdUrl is mq%3Drabbitmq%26queue%3Dpeople
	rawurl, _ := url.QueryUnescape(stdUrl)
	fmt.Printf("rawurl is %v\n", rawurl) // rawurl is mq=rabbitmq&queue=people
}

參考:
https://www.cnblogs.com/wanghui-garcia/p/10424463.html
https://studygolang.com/static/pkgdoc/pkg/net_url.htm

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章