


Поисковая строка содержит C++ guide, а фильтр допускает сразу две метки. Если собрать запрос конкатенацией, плюс можно перепутать с пробелом, а повтор ключа потерять. На Mentoring.digital используем url.Values и проверим результат обратным разбором.
url.Values связывает строковый ключ со срезом строк. Это позволяет хранить несколько значений одного параметра. Метод Add добавляет ещё одно значение, а Set заменяет все значения этого ключа одним. Кодирование выполняется после того, как структура собрана.
package main
import (
"fmt"
"net/url"
)
func main() {
address, err := url.Parse("https://example.test/search")
if err != nil {
panic(err)
}
query := url.Values{}
query.Set("q", "C++ guide")
query.Add("tag", "go")
query.Add("tag", "sql")
address.RawQuery = query.Encode()
fmt.Println(address.String())
restored, err := url.ParseQuery(address.RawQuery)
if err != nil {
panic(err)
}
fmt.Println(restored.Get("q"))
fmt.Println(restored["tag"])
}Ожидаемый адрес: https://example.test/search?q=C%2B%2B+guide&tag=go&tag=sql. Затем выводятся C++ guide и [go sql]. Пример только собирает и разбирает адрес, не отправляя HTTP-запрос.
Encode() сортирует ключи и кодирует параметры. Пробел в строке запроса представляется знаком +, а буквальный плюс знаком %2B. При обратном разборе исходное значение восстанавливается. Передавайте в Set обычный текст, а не заранее обработанную строку: иначе знак процента может закодироваться повторно.
Правила строки запроса не следует применять ко всему пути URL. Для работы с адресом используйте разобранный url.URL, а в RawQuery присваивайте готовый результат Encode(). Для пользовательского адреса успешный разбор ещё не подтверждает, что схема и хост подходят вашему приложению.
После address.RawQuery = query.Encode() адрес содержит строку на этот момент. Последующий query.Set("tag", "java") заменит значения в структуре, но не обновит поле адреса автоматически. Чтобы получить новый адрес, выполните кодирование и присваивание ещё раз.
Get("tag") возвращает только первое значение. Если контракт разрешает несколько меток, читайте срез query["tag"]. Также различайте отсутствующий ключ и переданное пустое значение: один Get() не показывает эту разницу. Для записи инициализируйте карту через литерал, как в примере, или make(url.Values).
Сохраните случаи с пробелом, буквальным плюсом, кириллицей, пустым значением и двумя метками. Сравнивайте восстановленные значения и их количество, а не только красивый вид адреса. Для взаимодействия с сервером дополнительно проверьте, как он читает повторяющиеся параметры.
Работу со стандартной библиотекой можно отработать на курсе Go с наставником. Если контракт клиента и сервера уже расходится, подготовьте обезличенный пример запроса для разбора с ментором по Go.