Contents
10.14. net/url¶
网络请求在Web开发中是常见的操作,比如如何进行网络请求、构建对服务器端网络资源的访问。这些操作都可以使用内置库net/url和net/http来实现,本节先学习一个非常小的点路由。在Web开发中,包含如下3个步骤:
(1)设置访问方法:GET、POST、PATCH、DELETE。
(2)设置访问路径,即路由的设计。
(3)设置资源的响应形式,RESTful API风格的响应形式一般选择采用JSON数据格式。
路由:URL(统一资源定位符),唯一定位服务器上的资源。下面通过示例来学习URL一般包含哪些部分。
net/url 库用于解析url。
10.14.1. 1.示例-将字符串转换为URL类型¶
package main
import (
"fmt"
"net/url"
)
func UrlUsage() {
var urlString = "https://golang.org/pkg/net/url?name=xie&age=20"
urlPath, _ := url.Parse(urlString)
fmt.Println(fmt.Sprintf("%#v", urlPath))
// &url.URL{Scheme:"https", Opaque:"", User:(*url.Userinfo)(nil), Host:"golang.org", Path:"/pkg/net/url", RawPath:"", ForceQuery:false, RawQuery:"name=xie&age=20", Fragment:"", RawFragment:""}
v := urlPath.Query()
v.Set("name", "Wei")
urlPath.RawQuery = v.Encode()
fmt.Println(fmt.Sprintf("%#v", urlPath))
// &url.URL{Scheme:"https", Opaque:"", User:(*url.Userinfo)(nil), Host:"golang.org", Path:"/pkg/net/url", RawPath:"", ForceQuery:false, RawQuery:"age=20&name=Wei", Fragment:"", RawFragment:""}
}
func UrlUsageParams() {
rawUrl := "https://golang.org/pkg/net/url?name=xie&age=20"
urlParsed, _ := url.Parse(rawUrl)
fmt.Println(urlParsed.Query()) // map[age:[20] name:[xie]]
v := urlParsed.Query()
v.Del("name")
v.Add("school", "shanghai")
urlParsed.RawQuery = v.Encode()
fmt.Println(urlParsed) // https://golang.org/pkg/net/url?age=20&school=shanghai
}
func UrlValues() {
values := "name=xie&age=20"
v, _ := url.ParseQuery(values)
fmt.Println(v) // map[age:[20] name:[xie]]
v.Add("school", "shanghai")
fmt.Println(v) // map[age:[20] name:[xie] school:[shanghai]]
}
func main() {
UrlUsage()
UrlUsageParams()
UrlValues()
}
URL核心的操作如下:
(1)将字符串转化为URL类型。
(2)对请求参数的操作。后续在net/http库中经常能看到URL操作的影子。
10.14.2. 2.示例1¶
package main
import (
"fmt"
"log"
"net/url"
)
func main() {
// 定义url字符串
s1 := "https://www.abc.123.com/hello/abc/index.html?k1=world&k2=abc"
s2 := "postgres://username:password@host.com:5432/path?k=v#f"
// 解析url
u1, err := url.Parse(s1)
if err != nil {
log.Printf("解析失败, err: %v\n", err)
return
}
// 解析url
u2, err := url.Parse(s2)
if err != nil {
log.Fatalf("解析失败, err: %v\n", err)
}
// 打印解析结构
fmt.Println(u1)
fmt.Println(u2)
// 打印解析结构的类型
fmt.Printf("u1 type: %T\n", u1) // *url.URL
fmt.Printf("u2 type: %T\n", u2) // *url.URL
fmt.Println(u1.Scheme)
fmt.Println(u2.Scheme)
fmt.Println(u1.User)
fmt.Println(u2.User)
}
10.14.3. 3.示例2¶
redirect := "http://cm-wzry.cmcm.com/spread/jump?uri=http%3a%2f%2fa.app.qq.com%2fo%2fsimple.jsp%3fpkgname%3dcom.cmcm.gamemaster%26f%3d6"
// 编码
encodeurl := url.QueryEscape(redirect)
fmt.Println(encodeurl)
// 解码
decodeurl, err := url.QueryUnescape(encodeurl)
if err != nil {
panic(err)
}
fmt.Println(decodeurl)
url.Parse() 函数返回一个url.URL结构体和一个错误,url.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 '#'
RawFragment string // encoded fragment hint (see EscapedFragment method)
}
// User 字段包含了认证信息,*Userinfo内容如下:
type Userinfo struct {
username string
password string
passwordSet bool
}
// UserInfo 结构体有三个方法:
// 返回 username
func (u *Userinfo) Username() string
// 返回 password 和 passwordSet
func (u *Userinfo) Password() (string, bool)
// String returns the encoded userinfo information in the standard form
// of "username[:password]".
func (u *Userinfo) String() string {
if u == nil {
return ""
}
s := escape(u.username, encodeUserPassword)
if u.passwordSet {
s += ":" + escape(u.password, encodeUserPassword)
}
return s
}
10.14.4. 4.小结¶
URL用于唯一定位服务器上的资源,浏览网页实质上就是使用浏览器访问各种服务器上不同的资源。
浏览器渲染出服务器上能够让用户看到的资源,不同的请求参数能够访问到的资源不同,URL通过服务器地址、路径、请求参数等构造出访问不同服务器资源的形式。