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 string Opaque 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 empty RawQuery 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) //postgresfmt.Printf(“%v\n”, u.Opaque)fmt.Printf(“%v\n”, u.User) //user:passfmt.Printf(“%v\n”, u.Host) //host.com:5432fmt.Printf(“%v\n”, u.Path) // /path1/path2/path3fmt.Printf(“%v\n”, u.RawPath)fmt.Printf(“%v\n”, u.ForceQuery) //falsefmt.Printf(“%v\n”, u.RawQuery) //k=v&k1=v1&k2=v2fmt.Printf(“%v\n”, u.Fragment) //ffmt.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) //mailtofmt.Printf(“%v\n”, u.Opaque) //coding@gmail.comURL.User
URL结构体中User字段包含了所有的认证信息??url.Userinfo??
type Userinfo struct { username string password string passwordSet 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.Hostfmt.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.com fmt.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: httpt.Logf(“url.Host: %v\f”, u.Host) //url.Host: www.baidu.comt.Logf(“url.Path: %v\f”, u.Path) //url.Path: /searcht.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) string
PathEscape将路径字符串转义,以便将其安全地放置在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%23footerdecodeurl, 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%23footerQueryUnescape执行与QueryEscape的逆转换func QueryUnescape(s string) (string, error)
例如:
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.ParseQueryfunc 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.RawQueryfmt.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]) //1fmt.Printf(“%v\n”, values[“name”][0]) //adminfmt.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.RawQuery values, 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.Queryfunc (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.Valuestype Values map[string][]stringfunc (v Values) Get(key string) stringfunc (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 []string for 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
【本文来源:香港服务器租用 st.html欢迎留下您的宝贵建议】每个人在他的人生发轫之初,总有一段时光,