Go URL
URL簡介
URL全稱Uniform Resource Location統(tǒng)一資源定位符,用于定位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 | 方案/協(xié)議,比如http、https、ftp、file… |
| host | 主機(jī)名或IP地址,用于定位網(wǎng)絡(luò)位置 |
| port | 服務(wù)端口 |
| path | 主機(jī)上的資源路徑 |
| query | 查詢字符串,使用&連接符鏈接的鍵值對。 |
| fragment | 分段字段 |
URL編碼
- URL不能有非ASCII字符,非ASCII使用%后跟兩位16進(jìn)制數(shù)表示。
- URL中不能存在空格,空格使用+表示。
| ~ | %7 |
| Space | %20 |
| % | %25 |
net/url
net包對于網(wǎng)絡(luò)I/O提供了便攜式接口,包括TCP/IP、UDP、域名解析、UNIX Socket。盡管net包提供了大量訪問底層的接口,但大多數(shù)情況下,客戶端僅僅只需要最基本的接口。
Golang標(biāo)準(zhǔn)庫net/url包
- 可用于獲取URL屬性
- 解析URL并實現(xiàn)查詢轉(zhuǎn)義
URL解讀
URL結(jié)構(gòu)體
type URL struct {Scheme stringOpaque string // 編碼后的不透明數(shù)據(jù)User *Userinfo // 用戶名和密碼信息Host string // 主機(jī)地址 或 主機(jī):端口Path string // path (relative paths may omit leading slash)RawPath string // 詳細(xì)資源地址ForceQuery bool // append a query ('?') even if RawQuery is emptyRawQuery string // 已編碼查詢字符串Fragment string // 引用片段可用于表示文檔位置RawFragment string // encoded fragment hint (see EscapedFragment method) }url.Parse
函數(shù)簽名
func Parse(rawurl string) (*URL, error)- 將原生的rawurl字符串解析轉(zhuǎn)換為URL結(jié)構(gòu)體,進(jìn)而獲取URL的相關(guān)屬性。
- 原生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結(jié)構(gòu)體中User字段包含了所有的認(rèn)證信息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同時包含主機(jī)名和端口,若端口存在則需要分割后才能提取。
例如:
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結(jié)構(gòu)體
url.ParseRequestURI原生URL是一個絕對URL或絕對路徑
url.ParseRequestURI會忽略URL中的fragment分片參數(shù)
例如:
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字符轉(zhuǎn)義為使用%后跟2位16進(jìn)制數(shù)的形式,采用PathUnescape方法解碼還原為原始模式。
func PathEscape(s string) stringPathEscape將路徑字符串轉(zhuǎn)義,以便將其安全地放置在URL路徑段中。
func PathUnescape(s string) (string, error)- PathUnescape執(zhí)行與PathEscape的逆轉(zhuǎn)換
- PathUnescape和QueryUnescape相同,只是PathUnescape不會將+加號轉(zhuǎn)換為空格。
例如:
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會將空格轉(zhuǎn)換為 %20
- PathEscape不會對URL中的:和&進(jìn)行轉(zhuǎn)義編碼
url.QueryEscape
- 對URL的查詢字符串進(jìn)行編碼和解碼
- QueryEscape將URL中的查詢字符串轉(zhuǎn)義,以便安全地放置到URL查詢字符串中。
URL中不允許存在空格和非ASCII字符,如果URL的查詢字符串query字符串中存在空格和ASCII字符則可采用url.QueryEscape將非ASCII字符轉(zhuǎn)化為使用%后跟2位16進(jìn)制數(shù)的形式,采用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執(zhí)行與QueryEscape的逆轉(zhuǎn)換
例如:
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會將空格轉(zhuǎn)換為+加號
- QueryEscape會將/路徑分隔符轉(zhuǎn)換為%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轉(zhuǎn)換為查詢字符串
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傳遞過來的參數(shù)編碼為以&連接的字符串
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總結(jié)
- 上一篇: Squid服务介绍
- 下一篇: Go go-metrics