Existe-t-il une méthode native pour les paramètres d'URL internes dans Go
natif?
Par exemple, si j'ai une URL: http://localhost:8080/blob/123/test
Je souhaite utiliser cette URL comme /blob/{id}/test
.
Il ne s'agit pas de trouver des bibliothèques go
. Je commence par la question de base, est-ce que cela va fournir une facilité de base pour le faire en mode natif.
Il n'y a pas de méthode simple pour le faire, mais ce n'est pas difficile à faire.
Voici comment je le fais, sans ajouter de bibliothèque particulière. Il est placé dans une fonction afin que vous puissiez invoquer une simple fonction getCode()
dans votre gestionnaire de requêtes.
Fondamentalement, vous venez de diviser le r.URL.Path
en pièces, puis analysez les pièces.
// Extract a code from a URL. Return the default code if code
// is missing or code is not a valid number.
func getCode(r *http.Request, defaultCode int) (int, string) {
p := strings.Split(r.URL.Path, "/")
if len(p) == 1 {
return defaultCode, p[0]
} else if len(p) > 1 {
code, err := strconv.Atoi(p[0])
if err == nil {
return code, p[1]
} else {
return defaultCode, p[1]
}
} else {
return defaultCode, ""
}
}
Eh bien, sans bibliothèques externes, vous ne pouvez pas, mais je peux recommander deux excellentes:
httprouter - https://github.com/julienschmidt/httprouter - est extrêmement rapide et très léger. Il est plus rapide que le routeur de la bibliothèque standard et crée 0 allocations par appel, ce qui est parfait dans un langage GCed.
Gorilla Mux - http://www.gorillatoolkit.org/pkg/mux - Très populaire, belle interface, belle communauté.
Exemple d'utilisation de httprouter:
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("/hello/:name", Hello)
log.Fatal(http.ListenAndServe(":8080", router))
}
Que diriez-vous d'écrire votre propre générateur d'URL (étendre net/url
un peu) comme ci-dessous.
// --- This is how does it work like --- //
url, _ := rest.NewURLGen("http", "stack.over.flow", "1234").
Pattern(foo/:foo_id/bar/:bar_id).
ParamQuery("foo_id", "abc").
ParamQuery("bar_id", "xyz").
ParamQuery("page", "1").
ParamQuery("offset", "5").
Do()
log.Printf("url: %s", url)
// url: http://stack.over.flow:1234/foo/abc/bar/xyz?page=1&offset=5
// --- Your own url generator would be like below --- //
package rest
import (
"log"
"net/url"
"strings"
"straas.io/base/errors"
"github.com/jinzhu/copier"
)
// URLGen generates request URL
type URLGen struct {
url.URL
pattern string
paramPath map[string]string
paramQuery map[string]string
}
// NewURLGen new a URLGen
func NewURLGen(scheme, Host, port string) *URLGen {
h := Host
if port != "" {
h += ":" + port
}
ug := URLGen{}
ug.Scheme = scheme
ug.Host = h
ug.paramPath = make(map[string]string)
ug.paramQuery = make(map[string]string)
return &ug
}
// Clone return copied self
func (u *URLGen) Clone() *URLGen {
cloned := &URLGen{}
cloned.paramPath = make(map[string]string)
cloned.paramQuery = make(map[string]string)
err := copier.Copy(cloned, u)
if err != nil {
log.Panic(err)
}
return cloned
}
// Pattern sets path pattern with placeholder (format `:<holder_name>`)
func (u *URLGen) Pattern(pattern string) *URLGen {
u.pattern = pattern
return u
}
// ParamPath builds path part of URL
func (u *URLGen) ParamPath(key, value string) *URLGen {
u.paramPath[key] = value
return u
}
// ParamQuery builds query part of URL
func (u *URLGen) ParamQuery(key, value string) *URLGen {
u.paramQuery[key] = value
return u
}
// Do returns final URL result.
// The result URL string is possible not escaped correctly.
// This is input for `gorequest`, `gorequest` will handle URL escape.
func (u *URLGen) Do() (string, error) {
err := u.buildPath()
if err != nil {
return "", err
}
u.buildQuery()
return u.String(), nil
}
func (u *URLGen) buildPath() error {
r := []string{}
p := strings.Split(u.pattern, "/")
for i := range p {
part := p[i]
if strings.Contains(part, ":") {
key := strings.TrimPrefix(p[i], ":")
if val, ok := u.paramPath[key]; ok {
r = append(r, val)
} else {
if i != len(p)-1 {
// if placeholder at the end of pattern, it could be not provided
return errors.Errorf("placeholder[%s] not provided", key)
}
}
continue
}
r = append(r, part)
}
u.Path = strings.Join(r, "/")
return nil
}
func (u *URLGen) buildQuery() {
q := u.URL.Query()
for k, v := range u.paramQuery {
q.Set(k, v)
}
u.RawQuery = q.Encode()
}
Pas question sans bibliothèque standard. Pourquoi vous ne voulez pas essayer une bibliothèque? Je pense que ce n'est pas si difficile de l'utiliser, allez simplement chercher bla bla bla
J'utilise Beego . Son style MVC.