среда, 29 сентября 2021 г.

Пакет net/url в Golang

Пакет url анализирует URL-адреса и реализует экранирование запросов.

Функция PathEscape

func PathEscape(s string) string

PathEscape экранирует строку, чтобы ее можно было безопасно разместить внутри сегмента пути URL, заменяя при необходимости специальные символы (включая /) последовательностями %XX.

Пример использования функции PathEscape

package main

import (
    "fmt"
    "net/url"
)

func main() {
    space := url.PathEscape("one two")
    fmt.Println(space)
    
    percent := url.PathEscape("10%")
    fmt.Println(percent)
    
    symbols := url.PathEscape(" ?&=#+%!<>#\"{}|\\^[]`☺\t:/@$'()*,;")
    fmt.Println(symbols)
}

Вывод:

one%20two
10%25
%20%3F&=%23+%25%21%3C%3E%23%22%7B%7D%7C%5C%5E%5B%5D%60%E2%98%BA%09:%2F@$%27%28%29%2A%2C%3B

Пример в песочнице https://play.golang.org/p/LNmUJmU8uaq

Функция PathUnescape

func PathUnescape(s string) (string, error)

PathUnescape выполняет обратное преобразование PathEscape, преобразуя каждую 3-байтовую закодированную подстроку формы "%AB" в шестнадцатеричный байт 0xAB. Он возвращает ошибку, если за любым % не следуют две шестнадцатеричные цифры.

PathUnescape идентичен QueryUnescape, за исключением того, что он не отменяет экранирование '+' на ' ' (пробел).

Пример использования функции PathUnescape

package main

import (
	"fmt"
	"net/url"
)

func main() {
	space, err := url.PathUnescape("one%20two")
	if err != nil {
		fmt.Println(err.Error())
	}
	fmt.Println(space)
	
	percent, err := url.PathUnescape("10%25")
	if err != nil {
		fmt.Println(err.Error())
	}
	fmt.Println(percent)
	
	symbols, err := url.PathUnescape("%20%3F&=%23+%25%21%3C%3E%23%22%7B%7D%7C%5C%5E%5B%5D%60%E2%98%BA%09:%2F@$%27%28%29%2A%2C%3B")
	if err != nil {
		fmt.Println(err.Error())
	}
	fmt.Println(symbols)
}

Вывод:

one two
10%
 ?&=#+%!<>#"{}|\^[]`☺	:/@$'()*,;

Пример в песочнице https://play.golang.org/p/RevOg4UxSG7

Функция QueryEscape

func QueryEscape(s string) string

QueryEscape экранирует строку, чтобы ее можно было безопасно поместить в URL-запрос.

Пример использования функции QueryEscape

package main

import (
    "fmt"
    "net/url"
)

func main() {
    space := url.QueryEscape("one two")
    fmt.Println(space)
    
    percent := url.QueryEscape("10%")
    fmt.Println(percent)
    
    symbols := url.QueryEscape(" ?&=#+%!<>#\"{}|\\^[]`☺\t:/@$'()*,;")
    fmt.Println(symbols)
}

Вывод:

one+two
10%25
+%3F%26%3D%23%2B%25%21%3C%3E%23%22%7B%7D%7C%5C%5E%5B%5D%60%E2%98%BA%09%3A%2F%40%24%27%28%29%2A%2C%3B

Пример в песочнице https://play.golang.org/p/hfKAuFsV00i

Функция QueryUnescape

func QueryUnescape(s string) (string, error)

QueryUnescape выполняет обратное преобразование QueryEscape, преобразуя каждую 3-байтовую закодированную подстроку формы "%AB" в шестнадцатеричный байт 0xAB. Он возвращает ошибку, если за любым % не следуют две шестнадцатеричные цифры.

Пример использования функции QueryUnescape

package main

import (
    "fmt"
    "net/url"
)

func main() {
    space, err := url.QueryUnescape("one+two")
    if err != nil {
        fmt.Println(err.Error())
    }
    fmt.Println(space)
    
    percent, err := url.QueryUnescape("10%25")
    if err != nil {
        fmt.Println(err.Error())
    }
    fmt.Println(percent)
    
    symbols, err := url.QueryUnescape("+%3F%26%3D%23%2B%25%21%3C%3E%23%22%7B%7D%7C%5C%5E%5B%5D%60%E2%98%BA%09%3A%2F%40%24%27%28%29%2A%2C%3B")
    if err != nil {
        fmt.Println(err.Error())
    }
    fmt.Println(symbols)
}

Вывод:

one two
10%
 ?&=#+%!<>#"{}|\^[]`☺	:/@$'()*,;

Пример в песочнице https://play.golang.org/p/cIDrkclH5Qa

Тип URL

type URL struct {
    Scheme      string
    Opaque      string    // закодированные непрозрачные данные
    User        *Userinfo // username и password информация
    Host        string    // host или host:port
    Path        string    // путь (в относительных путях может отсутствовать начальная косая черта)
    RawPath     string    // закодированный путь (EscapedPath)
    ForceQuery  bool      // добавить запрос ('?') даже если RawQuery пуст
    RawQuery    string    // закодированные значения запроса, без '?'
    Fragment    string    // фрагмент для ссылок, без '#'
    RawFragment string    // закодированный фрагмент (EscapedFragment)
}

URL представляет собой проанализированный URL-адрес (технически ссылка на URI).

Общая форма представленна как:

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

URL-адреса, которые не начинаются с косой черты после схемы, интерпретируются как:

scheme:opaque[?query][#fragment]

Обратите внимание, что поле Path хранится в декодированной форме: /%47%6f%2f становится /Go/. Как следствие, невозможно определить, какие косые черты в пути были косыми чертами в необработанном URL, а какие были %2f. Это различие редко бывает важным, но когда это так, код должен использовать RawPath, необязательное поле, которое устанавливается только в том случае, если кодировка по умолчанию отличается от Path.

Метод URL String использует метод EscapedPath для получения пути.

Пример использования типа URL

package main

import (
    "fmt"
    "log"
    "net/url"
)

func main() {
    u, err := url.Parse("http://bing.com/search?q=dotnet")
    if err != nil {
        log.Fatal(err)
    }
    u.Scheme = "https"
    u.Host = "google.com"
    q := u.Query()
    q.Set("q", "golang")
    u.RawQuery = q.Encode()
    fmt.Println(u)
}

Вывод

https://google.com/search?q=golang

Пример использования типа URL

package main

import (
    "fmt"
    "log"
    "net/url"
)

func main() {
    // Parse + String сохраняют первоначальное кодирование.
    u, err := url.Parse("https://example.com/foo%2fbar")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(u.Path)
    fmt.Println(u.RawPath)
    fmt.Println(u.String())
}

Вывод

/foo/bar
/foo%2fbar
https://example.com/foo%2fbar

Функция Parse

func Parse(rawURL string) (*URL, error)

Parse анализирует необработанный URL-адрес в структуру URL.

URL-адрес может быть относительным (путь без хоста) или абсолютным (начиная со схемы). Попытка проанализировать имя хоста и путь без схемы недопустима, но может не обязательно возвращать ошибку из-за неоднозначности синтаксического анализа.

Пример использования функции Parse

package main

import (
    "fmt"
    "log"
    "net/url"
)

func main() {
    u, err := url.Parse("http://bing.com/search?q=dotnet")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println("Scheme: ", u.Scheme)
    fmt.Println("Host: ", u.Host)
    fmt.Println("Path: ", u.Path)
    fmt.Println("RawQuery: ", u.RawQuery)
}

Вывод

Scheme:  http
Host:  bing.com
Path:  /search
RawQuery:  q=dotnet

Пример в песочнице https://play.golang.org/p/o5gLj5_fteS

Функция ParseRequestURI

func ParseRequestURI(rawURL string) (*URL, error)

ParseRequestURI анализирует необработанный URL-адрес в структуру URL. Предполагается, что URL-адрес был получен в HTTP-запросе, поэтому URL-адрес интерпретируется только как абсолютный URI или абсолютный путь. Предполагается, что строковый url не имеет суффикса #fragment. (Веб-браузеры удаляют #fragment перед отправкой URL-адреса на веб-сервер.)

Метод EscapedFragment

func (u *URL) EscapedFragment() string

EscapedFragment возвращает экранированную форму u.Fragment. В общем, существует несколько возможных экранированных форм любого фрагмента. EscapedFragment возвращает u.RawFragment, если это допустимое экранирование u.Fragment. В противном случае EscapedFragment игнорирует u.RawFragment и самостоятельно вычисляет экранированную форму. Метод String использует EscapedFragment для построения своего результата. В общем, код должен вызывать EscapedFragment вместо непосредственного чтения u.RawFragment.

Пример использования метода EscapedFragment

package main

import (
    "fmt"
    "log"
    "net/url"
)

func main() {
    u, err := url.Parse("http://example.com/#x/y%2Fz")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println("Fragment:", u.Fragment)
    fmt.Println("RawFragment:", u.RawFragment)
    fmt.Println("EscapedFragment:", u.EscapedFragment())
}

Вывод

Fragment: x/y/z
RawFragment: x/y%2Fz
EscapedFragment: x/y%2Fz

Пример в песочнице https://play.golang.org/p/Q-I-8bfoXFO

Метод EscapedPath

func (u *URL) EscapedPath() string

EscapedPath возвращает экранированную форму u.Path. Как правило, у любого пути есть несколько возможных экранированных форм. EscapedPath возвращает u.RawPath, если это действительное экранирование u.Path. В противном случае EscapedPath игнорирует u.RawPath и вычисляет экранированную форму самостоятельно. Методы String и RequestURI используют EscapedPath для построения своих результатов. В общем, код должен вызывать EscapedPath вместо непосредственного чтения u.RawPath.

Пример использования метода EscapedPath

package main

import (
    "fmt"
    "log"
    "net/url"
)

func main() {
    u, err := url.Parse("http://example.com/x/y%2Fz")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println("Path:", u.Path)
    fmt.Println("RawPath:", u.RawPath)
    fmt.Println("EscapedPath:", u.EscapedPath())
}

Вывод

Path: /x/y/z
RawPath: /x/y%2Fz
EscapedPath: /x/y%2Fz

Пример в песочнице https://play.golang.org/p/xvc45jZkqq6

Метод Hostname

func (u *URL) Hostname() string

Hostname возвращает u.Host, удаляя любой допустимый номер порта, если он присутствует.

Если результат заключен в квадратные скобки, как буквальные адреса IPv6, квадратные скобки удаляются из результата.

Пример использования метода Hostname

package main

import (
    "fmt"
    "log"
    "net/url"
)

func main() {
    u, err := url.Parse("https://example.org:8000/path")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(u.Hostname())
    u, err = url.Parse("https://[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:17000")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(u.Hostname())
}

Вывод

example.org
2001:0db8:85a3:0000:0000:8a2e:0370:7334

Пример в песочнице https://play.golang.org/p/0MV8vkqssmO

Метод IsAbs

func (u *URL) IsAbs() bool

IsAbs сообщает, является ли URL абсолютным. Абсолютное означает, что у него непустая схема.

Пример использования метода IsAbs

package main

import (
    "fmt"
    "net/url"
)

func main() {
    u := url.URL{Host: "example.com", Path: "foo"}
    fmt.Println(u.IsAbs())
    u.Scheme = "http"
    fmt.Println(u.IsAbs())
}

Вывод

false
true

Пример в песочнице https://play.golang.org/p/UfOBOdHopyF

Метод MarshalBinary

func (u *URL) MarshalBinary() (text []byte, err error)

Преобразует URL в срез байтов, выдает ошибку если она возникает при преобразовании.

Пример использования метода MarshalBinary

package main

import (
    "fmt"
    "log"
    "net/url"
)

func main() {
    u, _ := url.Parse("https://example.org")
    b, err := u.MarshalBinary()
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("%s\n", b)
}

Вывод

https://example.org

Пример в песочнице https://play.golang.org/p/L2uSp9WIN1Y

Метод Parse

func (u *URL) Parse(ref string) (*URL, error)

Parse анализирует URL-адрес в контексте получателя. Предоставленный URL-адрес может быть относительным или абсолютным. Parse возвращает nil, ошибку при сбое синтаксического анализа, в противном случае его возвращаемое значение такое же, как ResolveReference.

Пример использования метода Parse

package main

import (
    "fmt"
    "log"
    "net/url"
)

func main() {
    u, err := url.Parse("https://example.org")
    if err != nil {
        log.Fatal(err)
    }
    rel, err := u.Parse("/foo")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(rel)
    _, err = u.Parse(":foo")
    if _, ok := err.(*url.Error); !ok {
        log.Fatal(err)
    }
}

Вывод

https://example.org/foo

Пример в песочнице https://play.golang.org/p/lyPqaigN1pw

Метод Port

func (u *URL) Port() string

Port возвращает часть порта u.Host без начального двоеточия.

Если u.Host не содержит допустимого числового порта, Port возвращает пустую строку.

Пример использования метода Port

package main

import (
    "fmt"
    "log"
    "net/url"
)

func main() {
    u, err := url.Parse("https://example.org")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(u.Port())
    u, err = url.Parse("https://example.org:8080")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(u.Port())
}

Вывод

8080

Пример в песочнице https://play.golang.org/p/xcP1_ozPxfG

Метод Query

func (u *URL) Query() Values

Query анализирует RawQuery и возвращает соответствующие значения. Он молча отбрасывает искаженные пары значений. Для проверки ошибок используйте ParseQuery.

Пример использования метода Query

package main

import (
    "fmt"
    "log"
    "net/url"
)

func main() {
    u, err := url.Parse("https://example.org/?a=1&a=2&b=&=3&&&&")
    if err != nil {
        log.Fatal(err)
    }
    q := u.Query()
    fmt.Println(q["a"])
    fmt.Println(q.Get("b"))
    fmt.Println(q.Get(""))
}

Вывод

[1 2]

3

Пример в песочнице https://play.golang.org/p/MJrTerqSaqd

Метод Redacted

func (u *URL) Redacted() string

Redacted аналогично String, но заменяет любой пароль на "xxxxx". Удаляется только пароль в u.URL.

Пример использования метода Redacted

package main

import (
    "fmt"
    "net/url"
)

func main() {
    u := &url.URL{
        Scheme: "https",
        User:   url.UserPassword("user", "password"),
        Host:   "example.com",
        Path:   "foo/bar",
    }
    fmt.Println(u.Redacted())
    u.User = url.UserPassword("me", "newerPassword")
    fmt.Println(u.Redacted())
}

Вывод

https://user:xxxxx@example.com/foo/bar
https://me:xxxxx@example.com/foo/bar

Пример в песочнице https://play.golang.org/p/FPsxk_4bbCV

Метод RequestURI

func (u *URL) RequestURI() string

RequestURI возвращает закодированный path?query или opaque?query строку, которая будет использоваться в HTTP-запросе для u.

Пример использования метода RequestURI

package main

import (
    "fmt"
    "log"
    "net/url"
)

func main() {
    u, err := url.Parse("https://example.org/path?foo=bar")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(u.RequestURI())
}

Вывод

/path?foo=bar

Пример в песочнице https://play.golang.org/p/QK-lScEgjou

Метод ResolveReference

func (u *URL) ResolveReference(ref *URL) *URL

ResolveReference разрешает ссылку URI на абсолютный URI из абсолютного базового URI u, согласно RFC 3986. Ссылка URI может быть относительной или абсолютной. ResolveReference всегда возвращает новый экземпляр URL, даже если возвращенный URL идентичен базовому или ref. Если ref является абсолютным URL, ResolveReference игнорирует base и возвращает копию ref.

Пример использования метода ResolveReference

package main

import (
    "fmt"
    "log"
    "net/url"
)

func main() {
    u, err := url.Parse("../../..//search?q=dotnet")
    if err != nil {
        log.Fatal(err)
    }
    base, err := url.Parse("http://example.com/directory/")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(base.ResolveReference(u))
}

Вывод

http://example.com/search?q=dotnet

Пример в песочнице https://play.golang.org/p/WGNUEkswSmY

Метод String

func (u *URL) String() string

String повторно собирает URL в допустимую строку URL-адреса. Общий вид результата - один из:

scheme:opaque?query#fragment
scheme://userinfo@host/path?query#fragment

Если u.Opaque не пусто, String использует первую форму; в противном случае используется вторая форма. Любые символы, отличные от ASCII, в host экранируются. Чтобы получить путь (path), String использует u.EscapedPath().

Во второй форме действуют следующие правила:

- если u.Scheme пуст, scheme: не отображается.
- если u.User равен nil, userinfo@ опускается.
- если u.Host пуст, host/ не указывается.
- если u.Scheme и u.Host пусты, а u.User - nil,
    вся часть scheme://userinfo@host/ опускается.
- если u.Host не пуст и u.Path начинается с /,
    форма host/path не добавляет свой /.
- если u.RawQuery пуст, ?query опускается.
- если u.Fragment пуст, #fragment опускается.

Пример использования метода String

package main

import (
    "fmt"
    "net/url"
)

func main() {
    u := &url.URL{
        Scheme:   "https",
        User:     url.UserPassword("me", "pass"),
        Host:     "example.com",
        Path:     "foo/bar",
        RawQuery: "x=1&y=2",
        Fragment: "anchor",
    }
    fmt.Println(u.String())
    u.Opaque = "opaque"
    fmt.Println(u.String())
}

Вывод

https://me:pass@example.com/foo/bar?x=1&y=2#anchor
https:opaque?x=1&y=2#anchor

Пример в песочнице https://play.golang.org/p/trgWI4TlgAP

Метод UnmarshalBinary

func (u *URL) UnmarshalBinary(text []byte) error

Преобразует срез байтов и наполняет поля структуры URL, на которой был вызван. Возвращает ошибку в случае ее возникновения при анализе среза байтов.

Пример использования метода UnmarshalBinary

package main

import (
    "fmt"
    "log"
    "net/url"
)

func main() {
    u := &url.URL{}
    err := u.UnmarshalBinary([]byte("https://example.org/foo"))
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("%s\n", u)
}

Вывод

https://example.org/foo

Пример в песочнице https://play.golang.org/p/SyeYQ-6_Vy4

Тип Values

type Values map[string][]string

Values сопоставляет строковый ключ со списком значений. Обычно он используется для параметров запроса и значений формы. В отличие от карты http.Header, ключи в карте Values чувствительны к регистру.

Пример использования типа Values

package main

import (
    "fmt"
    "net/url"
)

func main() {
    v := url.Values{}
    v.Set("name", "Ava")
    v.Add("friend", "Jess")
    v.Add("friend", "Sarah")
    v.Add("friend", "Zoe")
    fmt.Println(v.Encode())
    fmt.Println(v.Get("name"))
    fmt.Println(v.Get("friend"))
    fmt.Println(v["friend"])
    fmt.Println(v.Has("name"))
    v.Del("name")
    fmt.Println(v.Encode())
}

Вывод

friend=Jess&friend=Sarah&friend=Zoe&name=Ava
Ava
Jess
[Jess Sarah Zoe]
true
friend=Jess&friend=Sarah&friend=Zoe

Пример в песочнице https://play.golang.org/p/9Gvyq0Rnlx7

Функция ParseQuery

func ParseQuery(query string) (Values, error)

ParseQuery анализирует строку запроса в кодировке URL и возвращает карту, в которой перечислены значения, указанные для каждого ключа. ParseQuery всегда возвращает ненулевую карту, содержащую все найденные допустимые параметры запроса; err описывает первую обнаруженную ошибку декодирования, если таковая имеется.

Ожидается, что запрос будет списком настроек ключ = значение, разделенных амперсандами. Параметр без знака равенства интерпретируется как ключ, установленный на пустое значение. Параметры, содержащие точку с запятой без кодировки URL, считаются недействительными.

Пример использования функции ParseQuery

package main

import (
    "encoding/json"
    "fmt"
    "log"
    "net/url"
    "strings"
)

func main() {
    m, err := url.ParseQuery(`x=1&y=2&y=3`)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(toJSON(m))
}

func toJSON(m interface{}) string {
    js, err := json.Marshal(m)
    if err != nil {
        log.Fatal(err)
    }
    return strings.ReplaceAll(string(js), ",", ", ")
}

Вывод

{"x":["1"], "y":["2", "3"]}

Пример в песочнице https://play.golang.org/p/3ytJDMl5P5y

Методы типа Values

func (v Values) Add(key, value string)

Add добавляет значение к ключу. Он добавляется к любым существующим значениям, связанным с ключом.

func (v Values) Del(key string)

Del удаляет значения, связанные с ключом.

func (v Values) Encode() string

Encode кодирует значения в форму "закодированный URL" ("bar=baz&foo=quux"), отсортированные по ключу.

func (v Values) Get(key string) string

Get получает первое значение, связанное с данным ключом. Если с ключом не связаны никакие значения, Get возвращает пустую строку. Чтобы получить доступ к нескольким значениям, используйте карту напрямую.

func (v Values) Has(key string) bool

Has проверяет, установлен ли данный ключ.

func (v Values) Set(key, value string)

Set устанавливает значение ключа. Он заменяет любые существующие значения.


Читайте также:


Комментариев нет:

Отправить комментарий