Значения необязательного запроса Gorilla mux

Я работал над проектом Go, где в качестве маршрутизатора используется gorilla / mux.

Мне нужно иметь возможность иметь значения запроса, связанные с маршрутом, но эти значения должны быть необязательными. Это означает, что я хотел бы поймать и /articles/123, и /articles/123?key=456 в одном обработчике.

Для этого я попытался использовать метод r.Queries, который принимает пары ключ / значение: router.

  Path("/articles/{id:[0-9]+}").Queries("key", "{[0-9]*?}")

но это делает необязательным только значение (456), но не key. Таким образом, допустимы и /articles/123?key=456, и /articles/123?key=, но не /articles/123.

Изменить: еще одно требование заключается в том, что после регистрации маршрута я хотел бы построить их программно, и я не могу понять, как использовать r.Queries, хотя в документации конкретно указано, что это возможно (https://github.com/gorilla/mux#registered-urls).

Ответ @jmaloney работает, но не позволяет создавать URL-адреса из имен.


person stassinari    schedule 28.07.2017    source источник
comment
Один подход: stackoverflow.com/questions/43379942/   -  person user94559    schedule 28.07.2017
comment
@smarx Я видел этот вопрос, но есть две причины, по которым он не работает для меня: 1. он не позволяет мне использовать mux.Vars(req)["tab"] в моем обработчике 2. он не позволяет мне создавать зарегистрированные URL-адреса по имени (я обновил вопрос)   -  person stassinari    schedule 28.07.2017


Ответы (3)


Я бы просто дважды зарегистрировал вашего обработчика.

router.Path("/articles/{id:[0-9]+}").
    Queries("key", "{[0-9]*?}").
    HandlerFunc(YourHandler).
    Name("YourHandler")

router.Path("/articles/{id:[0-9]+}").HandlerFunc(YourHandler)

Вот рабочая программа для демонстрации. Обратите внимание, что я использую r.FormValue для получения параметра запроса.

Примечание: убедитесь, что у вас установлена ​​последняя версия go get -u github.com/gorilla/mux, поскольку недавно была исправлена ​​ошибка, связанная с невозможностью добавления параметров запроса в построенные URL.

package main

import (
    "fmt"
    "log"
    "net/http"

    "github.com/gorilla/mux"
)

var router = mux.NewRouter()

func main() {
    router.Path("/articles/{id:[0-9]+}").Queries("key", "{key}").HandlerFunc(YourHandler).Name("YourHandler")
    router.Path("/articles/{id:[0-9]+}").HandlerFunc(YourHandler)

    if err := http.ListenAndServe(":9000", router); err != nil {
        log.Fatal(err)
    }
}

func YourHandler(w http.ResponseWriter, r *http.Request) {
    id := mux.Vars(r)["id"]
    key := r.FormValue("key")

    u, err := router.Get("YourHandler").URL("id", id, "key", key)
    if err != nil {
        http.Error(w, err.Error(), 500)
        return
    }

    // Output:
    // /articles/10?key=[key]
    w.Write([]byte(u.String()))
}
person jmaloney    schedule 28.07.2017
comment
Я пытался это сделать, и сработало, хотя не знаю, взлом это или нет. Единственная проблема в том, что я хотел бы использовать зарегистрированные URL-адреса для обратного построения URL-адресов по имени и обработки значений запроса с их использованием, и это, похоже, не работает. Обновлю вопрос. - person stassinari; 28.07.2017
comment
@stassinari Я думаю, что мое недавнее изменение должно решить ваши проблемы. - person jmaloney; 28.07.2017
comment
Спасибо @jmaloney, мне удалось заставить его работать. Один вопрос: есть ли причина, по которой вы используете r.FormValue вместо mux.Vars? Кажется, я могу заставить его работать - person stassinari; 31.07.2017
comment
Кроме того, чтобы иметь возможность создавать URL-адреса как с параметрами, так и без них, я прибег к использованию двух разных имен для маршрутов, так как в вашем методе одно имя потеряно, а перегрузка маршрутов двумя идентичными именами приводит к путанице с мультиплексором и не кажется работать. - person stassinari; 31.07.2017
comment
@stassinari Я использую r.FormValue, поскольку он вернет пустую строку, если ключ не найден, key не будет найден с помощью mux.Vars, если запрос перешел ко второму обработчику, обработка этого случая также заставляет вас проверять, имеет ли карта это значение . Я назвал маршрут только с параметрами запроса, поскольку создание URL-адреса с пустыми запросами все еще действует и приводит к меньшему количеству кода и логики. Например, в приведенном выше коде, если пользователь выберет второй маршрут, на выходе будет просто /articles/10?key=, что совершенно нормально. - person jmaloney; 31.07.2017
comment
@stassinari этому вопросу почти 3 года. Есть ли в настоящее время лучший способ добавить необязательный параметр без двойной регистрации дескриптора? - person vrybas; 04.06.2020
comment
@vrybas Я должен сказать, что не разбирался в этом, это решение работало в то время, и мы его не меняли. Если вы найдете новые советы, поделитесь здесь или в новом ответе! - person stassinari; 05.06.2020
comment
Итак, если у меня есть 10 необязательных параметров, мне нужно объявить маршрут для каждой возможной комбинации? кажется утомительным .. - person sgt-hartman; 16.06.2021
comment
@ sgt-hartman Вы можете просто определить все 10 ваших аргументов в первом обработчике. Лично я бы не стал использовать эту функцию мультиплексора, если бы ожидал появления множества необязательных аргументов запроса. Я бы определил обработчик без каких-либо аргументов и при необходимости использовал бы пакет url для построения запроса url. Функция Queries кажется наиболее полезной, когда вы хотите иметь несколько обработчиков для одного и того же маршрута, но разделять их аргументами запроса. - person jmaloney; 17.06.2021
comment
@jmaloney Да, по своей природе строки запроса обычно используются как необязательные параметры. Обязательные параметры должны входить в URI. Было бы отличным дополнением к библиотеке, если бы она могла с этим справиться. - person sgt-hartman; 18.06.2021

Если вы регистрируете параметры запроса, они являются обязательными doc:

Все переменные, определенные в маршруте, являются обязательными, и их значения должны соответствовать соответствующим шаблонам.

Поскольку эти параметры являются необязательными, вам просто нужно проверить их внутри функции-обработчика: id, found := mux.Vars(r)["id"]. Где found покажет, является ли параметр в запросе или нет.

person Pavlo Strokov    schedule 28.07.2017

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

urlParams := request.URL.Query()

Это возвращает карту, которая содержит параметры URL в виде пар ключ / значение.

person Nick    schedule 01.12.2020