• Go Web:URLs


    URL也是一个结构体:

    type URL struct {
            Scheme     string
            Opaque     string    // encoded opaque data
            User       *Userinfo // username and password information
            Host       string    // host or host:port
            Path       string    // path (relative paths may omit leading slash)
            RawPath    string    // encoded path hint (see EscapedPath method)
            ForceQuery bool      // append a query ('?') even if RawQuery is empty
            RawQuery   string    // encoded query values, without '?'
            Fragment   string    // fragment for references, without '#'
    }
    

    URL结构表示解析之后的URL,一般格式为:

    [scheme:][//[userinfo@]host][/]path[?query][#fragment]
    

    由于path和query部分只能使用大小写字母、数字以及有限的几个特殊标点,其它所有的字符都需要进行URL编码:百分号+2位16进制数。例如,空格被编码为"%20",斜线被编码为"%2f",有时候query的value中空格会被编码为"+"。

    例如,query部分被编码后的内容如下:

    name=Hiram%20Veeblefeetzer&age=35&country=Madagascar+abc
    

    它表示3个key/value:name="Hiram Veeblefeetzer"age=35country=Madagascar abc

    关于URL,其中:

    • Host字段是包含host和port两部分的,如果需要分别返回host、port,使用URL.HostnameURL.Port
    • User字段包含了Username和Password,要分别返回它们,使用URL.User.Username()URL.User.Password()
    • Path字段表示解码后的URL路径,也就是不带"%"的普通字符串路径
    • RawPaht字段表示编码后的安全路径,即带上了"%"的路径
    • RawQuery字段表示编码后的Query,即打上了"%"的query字符串,它包含了所有key/value,要分离每个key/value,使用ParseQuery()方法将它们解析到一个map中

    URL解析示例

    使用URL的Parse(string)方法可以将字符串构造成一个URL对象,并返回这个URL对象的指针。

    现在使用这个方法来构造一个URL对象,并解析其中的各个部分:

    package main
    
    import "fmt"
    import "net/url"
    
    func main() {
    	// 将字符串构造成URL对象
    	s := "postgres://user:pass@host.com:5432/path?k=v#f"
    	u, err := url.Parse(s)
    	if err != nil {
    		panic(err)
    	}
    
    	// 获取schema部分
    	fmt.Println(u.Scheme)
    
    	// User字段包含了Username和Password,需要分别获取
    	fmt.Println(u.User)
    	fmt.Println(u.User.Username())
    	p, _ := u.User.Password()
    	fmt.Println(p)
    
    	// Host字段包含了hostname和port
    	fmt.Println(u.Host)
    	fmt.Println(u.Hostname())
    	fmt.Println(u.Port())
    
    	// 取得Path和Fragment字段
    	fmt.Println(u.Path)
    	fmt.Println(u.Fragment)
    
    	// 取得query的key/value
    	// 要取出各个key/value,使用ParseQuery()将RawQuery字段解析成map
    	// key是字符串,value是字符串的slice,如果有key相同,则多个值放进这个slice
    	fmt.Println(u.RawQuery)
    	m, _ := url.ParseQuery(u.RawQuery)
    	fmt.Println(m)
    	fmt.Println(m["k"][0])
    }
    

    结果:

    postgres
    user:pass
    user
    pass
    host.com:5432
    host.com
    5432
    /path
    f
    k=v
    map[k:[v]]
    v
    

    构造URL

    URL的Parse(string)方法可以将字符串构造成一个URL对象,URL的String()方法可以返回编码后的URL值。

    例如:

    urlstr := "http://www.cnblogs.com/f-ck-need-u"
    myurl,_ := url.Parse(urlstr)
    fmt.Println(myurl.String())
    

    输出:

    http://www.cnblogs.com/f-ck-need-u
    

    由于URL的path和query部分可能包含特殊字符,直接使用纯字符串构造URL会不安全。应该使用另外两个函数将普通字符转换成编码后的字符:

    func PathEscape(s string) string
    func QueryEscape(s string) string
    

    再将编码之后的path和query作为Parse()方法的一部分。

    例如:

    package main
    
    import (
    	"fmt"
    	"net/url"
    )
    
    func main() {
    	// 要构造:http://www.example.int/下
    	// Path: search
    	// Query: food=pie aaa
    	//        action=like
    	// 的URL
    	s := "http://www.example.int"
    	p := "search"
    	path := url.PathEscape(p)
    
    	// query部分
    	qfood := "pie aaa"
    	qaction := "like"
    	qqfood := url.QueryEscape(qfood)
    	qqaction := url.QueryEscape(qaction)
    	// 将query组合起来
    	query := "food=" + qqfood + "&action=" + qqaction
    
    	// 构造url
    	myurlstr := s + "/" + path + "?" + query
    	myurl, err := url.Parse(myurlstr)
    	if err != nil {
    		panic(err)
    	}
    
    	// 解析URL
    	fmt.Println(myurl.String())
    	// 解析url的query部分
    	fmt.Println(myurl.RawQuery)
    	qmaps, _ := url.ParseQuery(myurl.RawQuery)
    	fmt.Println(qmaps["food"])
    	fmt.Println(qmaps["action"])
    }
    

    这很麻烦,对于Query部分,更好的方法是使用Values.Encode()方法,见后文。

    url Path部分

    在URL结构中:有Path和RawPath两个字段

    type URL struct{
    	...
    	Path     string    // path (relative paths may omit leading slash)
        RawPath  string    // encoded path hint (see EscapedPath method)
    	...
    }
    

    其中Path是解码后的路径,RawPath是编码后的路径。

    前面解释了PathEscape()函数,它是将字符串转换为编码后的字符串,可以直接将编码后的结果作为构造url的path部分,这样是最安全的构造方式。

    除此之外,还有一个EscapePath()方法:如果RawPath存在且有效,则直接返回RawPath字段的值,如果不存在,则EscapePath()自己计算一个编码后的路径。

    URL.String()方法是直接调用EscapePath()来构造路径部分的。

    Userinfo

    type Userinfo
        func User(username string) *Userinfo
        func UserPassword(username, password string) *Userinfo
        func (u *Userinfo) Password() (string, bool)
        func (u *Userinfo) String() string
        func (u *Userinfo) Username() string
    

    User()函数构造一个Userinfo,但只包含Username不包含password。

    UserPassword()函数构造一个Userinfo,包含Username和password,但因为明文显示,不建议使用。

    String()返回"username[:password]"格式的username和Password。

    Username()和Password()分别返回对应的部分。

    Query部分

    URL结构中有一个RawQuery字段:

    type URL struct {
    	...
    	RawQuery string
    	...
    }
    

    RawQuery字段是编码后的query。

    有几个方法:

    func (u *URL) Query() Values
    

    它读取RawQuery字段的值并返回Values类型。但会直接丢弃错误或畸形的query部分,如果要检查错误或畸形,使用ParseQuery()函数。

    注意上面Query()的返回值是Values类型,它是一个map结构:

    type Values map[string][]string
        func ParseQuery(query string) (Values, error)
        func (v Values) Add(key, value string)
        func (v Values) Del(key string)
        func (v Values) Encode() string
        func (v Values) Get(key string) string
        func (v Values) Set(key, value string)
    

    ParseQuery()函数解析给定字符串query并将query的各个部分填充到返回值类型Values的map结构中,同时会检查错误。

    Add()、Del()、Set()和Get()都用来操作Values的map结构,意义都很清晰。唯一需要注意的是,Add()是追加操作,Set()是替换已有值,如果操作的key不存在,则直接创建。

    Encode()是将Values中的数据根据key排序后编码成URL的query,且是编码后的query。

    下面是一个用法:

    package main
    
    import (
    	"fmt"
    	"net/url"
    )
    
    func main() {
    	s := "http://www.example.int"
    	p := "search"
    	path := url.PathEscape(p)
    
    	// query部分
    	values := url.Values{}
    	values.Set("food","pie aaa")
    	values.Add("action","like")
    	values.Add("name","abc")
    	values.Add("name","def")
    	values.Add("name","gh")
    	// Encode() == "action=like&food=pie+aaa&name=abc&name=def&name=gh"
    	query := values.Encode()
    
    	// 构造url
    	myurlstr := s + "/" + path + "?" + query
    	myurl, err := url.Parse(myurlstr)
    	if err != nil {
    		panic(err)
    	}
    
    	// 解析url
    	fmt.Println(myurl.String())
    }
    
  • 相关阅读:
    cJSON库源码分析
    cJSON 使用详解
    day23
    day22
    作业21
    day21
    作业20
    day20
    作业
    day19
  • 原文地址:https://www.cnblogs.com/f-ck-need-u/p/10020927.html
Copyright © 2020-2023  润新知