web-dev-qa-db-fra.com

Aller au mappage des paramètres d'URL

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.

26
Somesh

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, ""
        }
}
17
Jacob

Eh bien, sans bibliothèques externes, vous ne pouvez pas, mais je peux recommander deux excellentes:

  1. 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.

  2. 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))
}
12
Not_a_Golfer

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()
}
2
Browny Lin

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.

0
Arief Hidayatulloh