Отобразить параметры URL-адресов

Есть ли собственный способ для параметров url inplace в native Go?

Например, если у меня есть URL: http://localhost:8080/blob/123/test Я хочу использовать этот URL как /blob/{id}/test.

Я не хочу использовать внешнюю библиотеку и хочу сделать ее родной Go.

Ответ 1

Нет никакого встроенного простого способа сделать это, однако это непросто сделать.

Вот как я это делаю, не добавляя определенную библиотеку. Он помещается в функцию, так что вы можете вызвать простую функцию getCode() внутри вашего обработчика запросов.

В основном вы просто разделяете r.URL.Path на части, а затем анализируете части.

// 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, ""
        }
}

Ответ 2

Ну, без внешних библиотек вы не можете, но могу ли я рекомендовать два отличных:

  • httprouter - https://github.com/julienschmidt/httprouter - очень быстрый и легкий. Это быстрее, чем стандартный библиотечный маршрутизатор, и он создает 0 распределений за вызов, что отлично подходит для языка GCed.

  • Gorilla Mux - http://www.gorillatoolkit.org/pkg/mux - Очень популярный, приятный интерфейс, приятное сообщество.

Пример использования 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))
}

Ответ 3

Без стандартной библиотеки. Почему вы не хотите попробовать библиотеку? Я думаю, что его не так сложно использовать, просто пойдите, получите bla bla bla

Я использую Beego. Его стиль MVC.

Ответ 4

Если вам нужна структура, и вы думаете, что она будет медленной, потому что она "больше", чем маршрутизатор или сеть /http, тогда вы ошибаетесь.

Iris - это самая быстрая веб-фреймворк, которую вы когда-либо найдете, по всем тесты.

Установить

  go get gopkg.in/kataras/iris.v6

Шаблоны Django просты в диафрагме:

import (
    "gopkg.in/kataras/iris.v6"
    "gopkg.in/kataras/iris.v6/adaptors/httprouter"
    "gopkg.in/kataras/iris.v6/adaptors/view" // <-----

)

func main() {

    app := iris.New()
    app.Adapt(iris.DevLogger())
    app.Adapt(httprouter.New()) // you can choose gorillamux too
    app.Adapt(view.Django("./templates", ".html")) // <-----

    // RESOURCE: http://127.0.0.1:8080/hi
    // METHOD: "GET"
    app.Get("/hi", hi)

    app.Listen(":8080")
}

func hi(ctx *iris.Context){
   ctx.Render("hi.html", iris.Map{"Name": "iris"})
}

Ответ 5

Как насчет написания собственного генератора url (растяните net/url немного), как показано ниже.

// --- 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()
}