当前位置 : 主页 > 编程语言 > java >

Go URL

来源:互联网 收集:自由互联 发布时间:2022-07-17
URL简介 URL全称Uniform Resource Location统一资源定位符,用于定位Internet中待访问的文档或资源。 URL提供了一种定位Internet上任意资源的手段,资源可通过各种不同的方案(比如HTTP、FTP、S


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) //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.com

URL.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.User

username := userinfo.Username()
fmt.Printf("%v\n", username) //user

password, 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.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.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: 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=dotnet

url.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%23footer
  • QueryUnescape执行与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.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=0

values, 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.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) //1

url.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#footer

url.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​​转换为查询字符串

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=0

values.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


上一篇:400. 第 N 位数字【我亦无他唯手熟尔】
下一篇:没有了
网友评论