用go语言来修改URL的query部分后,得到的URL尽然没有变化,也就是说修改URL中的query失效了,追查go的URL实现源码才知道原因,这和go语言对URL的实现机制有关。
go语言的net/url包中有如下的api:
1 2 3 4 5 6 7 8 9 10 11 12 |
type URL func Parse(rawurl string) (url *URL, err error) func (u *URL) Parse(ref string) (*URL, error) func (u *URL) Query() Values func (u *URL) String() string type Values func ParseQuery(query string) (m Values, err 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) |
二话不说,先上段代码看看效果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
package main import ( "net/url" "fmt" ) func main(){ urlObj, _ := url.Parse("http://www.baidu.com/aaa?keyword=mp3") fmt.Println(urlObj.String()) urlObj.Query().Add("kkk", "vvv") fmt.Println(urlObj.Query().Get("kkk")) fmt.Println(urlObj.String()) } |
这段代码运行的结果是:
1 2 3 |
http://www.baidu.com/aaa?keyword=mp3 http://www.baidu.com/aaa?keyword=mp3 |
显然结果中并没有把参数kkk=vvv加到url中,直接从api看,应该会加进去的啊,那为啥?我开始对着api做了很多尝试,比如传值和指针的对比、试试编码解码等,最终结果都一样,修改后的URL没有变化。最后没招了,只能看go的源代码了。
1 2 3 4 5 6 7 8 9 10 |
// scheme://[userinfo@]host/path[?query][#fragment] type URL struct { Scheme string Opaque string // encoded opaque data User *Userinfo // username and password information Host string Path string RawQuery string // encoded query values, without '?' Fragment string // fragment for references, without '#' } |
从这里看到query在URL对象中不是以一个map的形式存储的,而是一个原生的字符串
1 2 3 4 5 |
// Query parses RawQuery and returns the corresponding values. func (u *URL) Query() Values { v, _ := ParseQuery(u.RawQuery) return v } |
从这里可以看到ParseQuery的参数为URL.RawQuery字段,根据参数的值传递机制,ParseQuery函数的返回值v是一个与u.RawQuery无关的一个Values对象,此时对Values对象进行AddSetDel的操作都不会改变u中的RawQuery。所以要想把修改URL对象,就需要把修改后的Values转成字符串,再赋值给u.RawQuery字段。看下修改后的代码:
1 2 3 4 5 6 7 8 9 |
func main(){ urlObj, _ := url.Parse("http://www.baidu.com/aaa?keyword=mp3") fmt.Println(urlObj.String()) v := urlObj.Query() v.Add("kkk", "vvv") urlObj.RawQuery = v.Encode() fmt.Println(urlObj.Query().Get("kkk")) fmt.Println(urlObj.String()) } |
这样运行结果就正确了:
1 2 3 |
http://www.baidu.com/aaa?keyword=mp3 vvv http://www.baidu.com/aaa?kkk=vvv&keyword=mp3 |
有时还是需要去研读源码和官方文档的,精华的东西都在源码中,这才是学习,而不是看着api,拿过来就用。