Go URL
URL簡介
URL全稱Uniform Resource Location統一資源定位符,用于定位Internet中待訪問的文檔或資源。
URL提供了一種定位Internet上任意資源的手段,資源可通過各種不同的方案(比如HTTP、FTP、SMTP)來訪問,因此URL語法隨著方案不同而不同。
<schema>://<user>:<password>@<host>:<port>/<path>:<params>?<query>#<frag>URL格式
scheme://[userinfo@]host[:port]/path[?query][#fragment] scheme://[userinfo]@[host]:[port]/path?key1=value1&key2=value2#fragment| scheme | 方案/協議,比如http、https、ftp、file… |
| host | 主機名或IP地址,用于定位網絡位置 |
| port | 服務端口 |
| path | 主機上的資源路徑 |
| query | 查詢字符串,使用&連接符鏈接的鍵值對。 |
| fragment | 分段字段 |
URL編碼
- URL不能有非ASCII字符,非ASCII使用%后跟兩位16進制數表示。
- URL中不能存在空格,空格使用+表示。
| ~ | %7 |
| Space | %20 |
| % | %25 |
net/url
net包對于網絡I/O提供了便攜式接口,包括TCP/IP、UDP、域名解析、UNIX Socket。盡管net包提供了大量訪問底層的接口,但大多數情況下,客戶端僅僅只需要最基本的接口。
Golang標準庫net/url包
- 可用于獲取URL屬性
- 解析URL并實現查詢轉義
URL解讀
URL結構體
type URL struct {Scheme stringOpaque string // 編碼后的不透明數據User *Userinfo // 用戶名和密碼信息Host string // 主機地址 或 主機:端口Path string // path (relative paths may omit leading slash)RawPath string // 詳細資源地址ForceQuery bool // append a query ('?') even if RawQuery is emptyRawQuery string // 已編碼查詢字符串Fragment string // 引用片段可用于表示文檔位置RawFragment string // encoded fragment hint (see EscapedFragment method) }url.Parse
函數簽名
func Parse(rawurl string) (*URL, error)- 將原生的rawurl字符串解析轉換為URL結構體,進而獲取URL的相關屬性。
- 原生URL可以是絕對地址,也可以是相對地址。
例如:
rawurl := "postgres://user:pass@host.com:5432/path1/path2/path3?k=v&k1=v1&k2=v2#f" u, err := url.Parse(rawurl) if err != nil {t.Fatal(err) }fmt.Printf("%v\n", u.Scheme) //postgres fmt.Printf("%v\n", u.Opaque) fmt.Printf("%v\n", u.User) //user:pass fmt.Printf("%v\n", u.Host) //host.com:5432 fmt.Printf("%v\n", u.Path) // /path1/path2/path3 fmt.Printf("%v\n", u.RawPath) fmt.Printf("%v\n", u.ForceQuery) //false fmt.Printf("%v\n", u.RawQuery) //k=v&k1=v1&k2=v2 fmt.Printf("%v\n", u.Fragment) //f fmt.Printf("%v\n", u.RawFragment)URL.Opaque
url.Opaque表示透明類型的URL,即Scheme后沒有//的URL。
rawurl := "mailto:coding@gmail.com" u, err := url.Parse(rawurl) if err != nil {panic(err) }fmt.Printf("%v\n", u.Scheme) //mailto fmt.Printf("%v\n", u.Opaque) //coding@gmail.comURL.User
URL結構體中User字段包含了所有的認證信息url.Userinfo
type Userinfo struct {username stringpassword stringpasswordSet bool }通過Userinfo.Username()方法獲取username字段值
func (u *Userinfo) Username() string {if u == nil {return ""}return u.username }通過Userinfo.Password()獲取password和passwordSet字段值
func (u *Userinfo) Password() (string, bool) {if u == nil {return "", false}return u.password, u.passwordSet }例如:
rawurl := "postgres://user:pass@host.com:5432/path1/path2/path3?k=v&k1=v1&k2=v2#f" u, err := url.Parse(rawurl) if err != nil {panic(err) } userinfo := u.Userusername := userinfo.Username() fmt.Printf("%v\n", username) //userpassword, ok := userinfo.Password() if ok {fmt.Printf("%v\n", password) //pass }URL.Host
url.Host同時包含主機名和端口,若端口存在則需要分割后才能提取。
例如:
rawurl := "postgres://user:pass@host.com:5432/path1/path2/path3?k=v&k1=v1&k2=v2#f" u, err := url.Parse(rawurl) if err != nil {panic(err) } host := u.Host fmt.Printf("%v\n", host) //host.com:5432 //判斷是否存在: ok := strings.Contains(host, ":") if ok {h := strings.Split(host, ":")fmt.Printf("%v\n", h) //[host.com 5432]addr := h[0]port := h[1]fmt.Printf("%v\n", addr) //host.comfmt.Printf("%v\n", port) //5432 }url.ParseRequestURI
url.ParseRequestURI解析原生URL為一個URL結構體
url.ParseRequestURI原生URL是一個絕對URL或絕對路徑
url.ParseRequestURI會忽略URL中的fragment分片參數
例如:
rawurl := "http://www.baidu.com/search?q=dotnet" u, err := url.ParseRequestURI(rawurl) if err != nil {t.Fatal(err) } t.Logf("url.Scheme: %v\f", u.Scheme) //url.Scheme: http t.Logf("url.Host: %v\f", u.Host) //url.Host: www.baidu.com t.Logf("url.Path: %v\f", u.Path) //url.Path: /search t.Logf("url.RawQuery: %v\f", u.RawQuery) //url.RawQuery: q=dotneturl.PathEscape
URL中不允許存在空格和非ASCII字符,如果URL的資源路徑path字符串中存在空格和ASCII字符則可采用url.PathEscape將非ASCII字符轉義為使用%后跟2位16進制數的形式,采用PathUnescape方法解碼還原為原始模式。
func PathEscape(s string) stringPathEscape將路徑字符串轉義,以便將其安全地放置在URL路徑段中。
func PathUnescape(s string) (string, error)- PathUnescape執行與PathEscape的逆轉換
- PathUnescape和QueryUnescape相同,只是PathUnescape不會將+加號轉換為空格。
例如:
rawurl := "http://www.baidu.com/search?id=1&name=管 理 員&pid=0#footer" encodeurl := url.PathEscape(rawurl) t.Log(encodeurl) http:%2F%2Fwww.baidu.com%2Fsearch%3Fid=1&name=%E7%AE%A1%20%E7%90%86%20%E5%91%98&pid=0%23footer decodeurl, err := url.PathUnescape(encodeurl) if err != nil {t.Fatal(err) } t.Log(decodeurl) http://www.baidu.com/search?id=1&name=管 理 員&pid=0#footer| / | %2F |
| ? | %3F |
| # | %23 |
| 空格 | %20 |
- PathEscape會將空格轉換為 %20
- PathEscape不會對URL中的:和&進行轉義編碼
url.QueryEscape
- 對URL的查詢字符串進行編碼和解碼
- QueryEscape將URL中的查詢字符串轉義,以便安全地放置到URL查詢字符串中。
URL中不允許存在空格和非ASCII字符,如果URL的查詢字符串query字符串中存在空格和ASCII字符則可采用url.QueryEscape將非ASCII字符轉化為使用%后跟2位16進制數的形式,采用QueryUnescape方法解碼還原為原始模式。
func QueryEscape(s string) string例如:
rawurl := "http://www.baidu.com/search?id=1&name=管 理 員&pid=0#footer" encodeurl := url.QueryEscape(rawurl) t.Log(encodeurl) http%3A%2F%2Fwww.baidu.com%2Fsearch%3Fid%3D1%26name%3D%E7%AE%A1+%E7%90%86+%E5%91%98%26pid%3D0%23footer- QueryUnescape執行與QueryEscape的逆轉換
例如:
rawurl := "http://www.baidu.com/search?id=1&name=管 理 員&pid=0#footer" encodeurl := url.QueryEscape(rawurl)decodeurl, err := url.QueryUnescape(encodeurl) if err != nil {t.Fatal(err) } t.Log(decodeurl) http://www.baidu.com/search?id=1&name=管 理 員&pid=0#footer| : | %3A |
| / | %2F |
| ? | %3F |
| & | %26 |
| # | %23 |
| 空格 | + |
- QueryEscape會將空格轉換為+加號
- QueryEscape會將/路徑分隔符轉換為%2F
url.ParseQuery
func ParseQuery(query string) (Values, error) {m := make(Values)err := parseQuery(m, query)return m, err }URL中的查詢字符串可采用url.ParseQuery解析生成一個url.Values字典實例。
例如:
rawurl := "http://www.baidu.com/search?id=1&name=admin&pid=0#footer" u, err := url.Parse(rawurl) if err != nil {panic(err) } query := u.RawQuery fmt.Printf("%v\n", query) //id=1&name=admin&pid=0values, err := url.ParseQuery(query) if err != nil {panic(err) } fmt.Printf("%v\n", values) //map[id:[1] name:[admin] pid:[0]] fmt.Printf("%v\n", values["id"][0]) //1 fmt.Printf("%v\n", values["name"][0]) //admin fmt.Printf("%v\n", values["pid"][0]) //0封裝:從URL的查詢字符串中通過鍵獲得值
func GetQueryStringField(rawurl string, key string) (string, error) {u, err := url.Parse(rawurl)if err != nil {return "", err}query := u.RawQueryvalues, err := url.ParseQuery(query)if err != nil {return "", err}value := values.Get(key)return value, nil } rawurl := "http://www.baidu.com/search?id=1&name=admin&pid=0#footer" id, err := GetQueryStringField(rawurl, "id") if err != nil {panic(err) } fmt.Printf("%v\n", id) //1url.Query
func (u *URL) Query() Values {v, _ := ParseQuery(u.RawQuery)return v } rawurl := "http://www.baidu.com/search?id=1&name=admin&pid=0#footer" u, err := url.Parse(rawurl) if err != nil {panic(err) }values := u.Query() fmt.Printf("%v\n", values) //map[id:[1] name:[admin] pid:[0]]id := values.Get("id") fmt.Printf("%v\n", id) //1重置查詢字符串鍵值對
rawurl := "http://www.baidu.com/search?id=1&name=admin&pid=0#footer" u, err := url.Parse(rawurl) if err != nil {panic(err) }values := u.Query() values.Set("id", "100")u.RawQuery = values.Encode() t.Log(u) //http://www.baidu.com/search?id=100&name=admin&pid=0#footerurl.Values
type Values map[string][]string func (v Values) Get(key string) string func (v Values) Set(key, value string) func (v Values) Add(key, value string) func (v Values) Del(key string) func (v Values) Encode() string將url.Values轉換為查詢字符串
func BuildHTTPQueryString(values url.Values) string {var keys []stringfor k := range values {keys = append(keys, k)}sort.Strings(keys)bb := bytes.Buffer{}for _, key := range keys {val := values.Get(key)bb.WriteString(key)bb.WriteString("=")bb.WriteString(val)bb.WriteString("&")}return strings.TrimRight(bb.String(), "&") } values := url.Values{} values.Add("id", "1") values.Add("name", "admin") values.Add("pid", "0")queryString := BuildHTTPQueryString(values) fmt.Printf("%v\n", queryString) //id=1&name=admin&pid=0values.Encode
例如:HTTP請求將URL傳遞過來的參數編碼為以&連接的字符串
values := url.Values{} values.Add("app_id", "2016073100129537") values.Add("out_trade_no", "2201010101") values.Add("method", "alipay.trade.app.pay") values.Add("notify_url", "http://203.86.24.181:3000/alipay") values.Add("timestamp", "2017-11-10 17:54:34") values.Add("sign_type", "RSA2") values.Add("version", "1.0") encode := values.Encode() fmt.Printf("%v\n", encode) app_id=2016073100129537&method=alipay.trade.app.pay¬ify_url=http%3A%2F%2F203.86.24.181%3A3000%2Falipay&out_trade_no=2201010101&sign_type=RSA2×tamp=2017-11-10+17%3A54%3A34&version=1.0總結
- 上一篇: Squid服务介绍
- 下一篇: Go go-metrics