Подстановочные знаки в шаблоне для http.HandleFunc - PullRequest
60 голосов
/ 03 июля 2011

При регистрации обработчиков в Go (язык) есть ли способ указать шаблоны в шаблоне?

Например:

http.HandleFunc("/groups/*/people", peopleInGroupHandler)

Где * может быть любым действительным URLстрока.Или это единственное решение, которое соответствует /groups и вычисляет остальное из функции обработчика (peopleInGroupHandler)?

Ответы [ 5 ]

82 голосов
/ 04 июля 2011

Шаблоны для http.Handler и http.HandleFunc не являются регулярными выражениями или глобусами. Нет способа указать подстановочные знаки. Они задокументированы здесь .

Тем не менее, не сложно создать собственный обработчик, который может использовать регулярные выражения или любой другой тип шаблона, который вы хотите. Вот пример, в котором используются регулярные выражения (скомпилированные, но не проверенные):

type route struct {
    pattern *regexp.Regexp
    handler http.Handler
}

type RegexpHandler struct {
    routes []*route
}

func (h *RegexpHandler) Handler(pattern *regexp.Regexp, handler http.Handler) {
    h.routes = append(h.routes, &route{pattern, handler})
}

func (h *RegexpHandler) HandleFunc(pattern *regexp.Regexp, handler func(http.ResponseWriter, *http.Request)) {
    h.routes = append(h.routes, &route{pattern, http.HandlerFunc(handler)})
}

func (h *RegexpHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    for _, route := range h.routes {
        if route.pattern.MatchString(r.URL.Path) {
            route.handler.ServeHTTP(w, r)
            return
        }
    }
    // no pattern matched; send 404 response
    http.NotFound(w, r)
}
54 голосов
/ 30 августа 2014

С 2011 года вы можете теперь (2014+) находить другие решения.
Например, пакет mux набора инструментов Gorilla Web предоставляет все виды вариантов маршрутизации:

  • Сопоставление с образцом в путях запроса, с необязательными регулярными выражениями.
  • Сопоставление с хостом и схемой URL, методом запроса, заголовком и значениями запроса.
  • Сопоставление на основе пользовательских функций.
  • Использование суб-маршрутизаторов для простой вложенной маршрутизации.

Может быть легко интегрировано в любую http-библиотеку BYOR (Bring your own Router), , как negroni .

Вот пример из статьи " Gorilla vs Pat против Routes: Mux Showdown ":

package main

import (
  "github.com/gorilla/mux"
  "log"
  "net/http"
)

func main() {
  rtr := mux.NewRouter()
  rtr.HandleFunc("/user/{name:[a-z]+}/profile", profile).Methods("GET")

  http.Handle("/", rtr)

  log.Println("Listening...")
  http.ListenAndServe(":3000", nil)
}

func profile(w http.ResponseWriter, r *http.Request) {
  params := mux.Vars(r)
  name := params["name"]
  w.Write([]byte("Hello " + name))
}

Иногда лучше не просто использовать еще один "волшебный »пакет, но поймите, что происходит под капотом

В этом случае« магия »определена в« gorilla/mux/regexp.go », и проверено здесь.
Идея состоит в том, чтобы извлечь именованные переменные, собрать регулярное выражение для созданияЗатем создайте «обратный» шаблон для построения URL-адресов и скомпилируйте регулярные выражения для проверки значений переменных, используемых при построении URL-адресов.

6 голосов
/ 14 октября 2015

Я просто хотел добавить julienschmidt/httprouter, который ведет себя как net/http, но с дополнительным параметром для значений url и поддержкой методов запроса:

https://github.com/julienschmidt/httprouter

package main

import (
    "fmt"
    "github.com/julienschmidt/httprouter"
    "net/http"
    "log"
)

func Index(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
    fmt.Fprint(w, "Welcome!\n")
}

func Hello(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
    fmt.Fprintf(w, "hello, %s!\n", ps.ByName("name"))
}

func main() {
    router := httprouter.New()
    router.GET("/", Index)
    router.GET("/hello/:name", Hello)

    log.Fatal(http.ListenAndServe(":8080", router))
}

Он также кажется немного более популярным, чем gorilla/mux (согласно GitHub), и утверждает, что ему требуется меньше памяти.

https://github.com/julienschmidt/go-http-routing-benchmark

1 голос
/ 10 сентября 2017

Вы можете проверить, как violetear обрабатывает шаблоны динамического + универсального (подстановочного) символа, это только для дополнения, например:

uuid := `[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}`
router.AddRegex(":uuid")
router.HandleFunc("/test/:uuid/:uuid", handleUUID, "GET,HEAD")

В этом случае запрос может иметь 2 разных UUIDS

Для динамического / подстановочного знака это может применяться:

http://api.violetear.org/command/ping/127.0.0.1
                        \______/\___/\________/
                            |     |      |
                             static      |
                                      dynamic

Для сопоставления IP может использоваться регулярное выражение:

router.AddRegex(":ip", `^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$`)
router.HandleFunc("/command/ping/:ip", ipHandler, "GET")

Или просто поймать все, разрешив только GET и HEAD методы:

router.HandleFunc("/command/ping/*", anyHandler, "GET, HEAD")

Дополнительные примеры можно найти здесь: https://violetear.org/post/how-it-works/

0 голосов
/ 04 декабря 2013

Beego, ответ на все вопросы веб-сервера Golang. Wetalk - это блог, созданный на Beego.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...