Подтвердить что ты не робот

Есть ли пакет для маршалинга из x-www-form-urlencoding в golang

Я хотел бы маршалировать и из x-www-form-urlencoding, подобно тому, как вы можете это сделать с помощью json или xml. Есть ли существующий пакет для этого или есть ли какие-либо документы о том, как его реализовать, если они не существуют?

4b9b3361

Ответ 1

gorilla/schema является популярным и ухоженным:

например.

func FormHandler(w http.RequestWriter, r *http.Request) {

    err := r.ParseForm()
    if err != nil {
         // handle error
    }
    person := new(Person) // Person being a struct type
    decoder := schema.NewDecoder()

    err = decoder.Decode(person, r.Form)
    if err != nil {
         // handle error
    }

}

goforms также является альтернативой.

Обновление от 23 мая 2015 года:

  • gorilla/schema по-прежнему является моим выбором как один из наиболее поддерживаемых пакетов map-to-struct, причем значения формы POST являются обычным прецедентом.
  • goji/param также довольно прост и имеет многие из тех же функций.
  • mholt/binding - это немного больше функций, упакованных на счет (IMO) немного более сложного API.

Я использую горилла/схему уже пару лет и не имел никаких серьезных проблем с ней. Я использую его в сочетании с vala для проверки входов (не ноль, слишком короткий, слишком длинный и т.д.), Прежде чем они попадут в БД.

Ответ 4

Пакет "github.com/pasztorpisti/qs" также может выстраивать/развязывать структуры в/из строк запроса и POST -ed формы.

Пример:

package main

import "fmt"
import "github.com/pasztorpisti/qs"

type Query struct {
    Search     string
    Page       int
    PageSize   int
    Categories []string `qs:"category"`
}

func main() {
    queryStr, err := qs.Marshal(&Query{
        Search:     "my search",
        Page:       2,
        PageSize:   50,
        Categories: []string{"c1", "c2"},
    })
    fmt.Println("Marshal-Result:", queryStr, err)

    var q Query
    err = qs.Unmarshal(&q, queryStr)
    fmt.Println("Unmarshal-Result:", q, err)

    // Output:
    // Marshal-Result: category=c1&category=c2&page=2&page_size=50&search=my+search <nil>
    // Unmarshal-Result: {my search 2 50 [c1 c2]} <nil>
}

Возможные точки продажи этого пакета:

  • Имена полей структуры автоматически отображаются в строке запроса snake_case. Для этого вам не нужно добавлять qs:"field_name" в тег поля структуры. Это можно изменить.
  • Модульная архитектура, которая позволяет заменять маршалистов и маркеристов даже для встроенных типов (например, bool, []byte) и добавлять поддержку для новых типов без изменения самого типа (например: добавить маршалинг и/или unmarshaling для time.Time). Вот пример.
  • Вы можете добавить опцию req в тег тега структуры, чтобы сделать поле обязательным во время разметки. Обратите внимание, что это скорее проверка, чем немаршалинг, а библиотеки golang обычно идут на разделение между ними, но я нашел эту опцию очень полезной, потому что она нужна часто, она проста и хорошо читается. Для тех, кто хочет избегать req и выполнять эту проверку отдельно после разметки: существует тег nil, который почти такой же, как и по умолчанию opt (который обозначает "необязательный" ), за исключением того, t инициализировать nil-указатели, когда заданные поля не находятся в строке немаршалированного запроса. Таким образом, код валидатора может обнаруживать недостающие поля, ища нулевые указатели после отмены маркера.
  • Пакет qs может определить, является ли сложный тип (например, ваша структура) маршализуемым, прежде чем фактически маршалировать экземпляр этого типа. Большинство пакетов маршала не могут это сделать даже после маршалинга экземпляра данного типа! Большинство маршалистов исследуют сложные типы, перемещая объект, маршалируемый и проверяя типы только для посещенных под-объектов. Это означает, что если сложный объект содержит контейнер (указатель, карту или срез), который пуст, тип элемента контейнера даже не проверяется. В контракте qs идет структура типа сложного объекта (а не самого объекта) при создании маршалера для типа, поэтому он терпит неудачу там, где он должен терпеть неудачу. Рассмотрим следующий код, в котором стандартный пакет "encoding/json" успешно маршалирует объект, тип которого содержит непереводимый тип:

    package main
    
    import (
        "encoding/json"
        "fmt"
        "reflect"
    
        "github.com/pasztorpisti/qs"
    )
    
    type NonMarshalable func()
    
    func jsonEmptyMap() {
        // Since the container is empty "encoding/json" doesn't examine the type
        // of its items. This results in an unexpected success.
        var m = map[string]NonMarshalable{}
        j, err := json.Marshal(m)
        fmt.Println(string(j), err)
        // Output:
        // {} <nil>
    }
    
    func jsonNonEmptyMap() {
        var m = map[string]NonMarshalable{
            "f": func() {},
        }
        j, err := json.Marshal(m)
        fmt.Println(string(j), err)
        // Output:
        //  json: unsupported type: main.NonMarshalable
    }
    
    func qsEmptyMap() {
        // qs.Marshal fails even if the container is empty because the first step
        // of qs.Marshal fails: It can't create the marshaler object for this type.
        var m = map[string]NonMarshalable{}
        s, err := qs.Marshal(m)
        fmt.Println(s, err)
        // Output:
        //  error getting marshaler for map value type main.NonMarshalable :: unhandled type: main.NonMarshalable
    }
    
    func qsTypeCheck() {
        // You don't even have to try to marshal an object to find out whether its
        // type is marshal-friendly. You can check the type directly. By doing this
        // at startup (e.g.: from init functions) you can avoid delaying runtime
        // errors.
        t := reflect.TypeOf((map[string]NonMarshalable)(nil))
        err := qs.CheckMarshalType(t)
        fmt.Println(err)
        // Output:
        // error getting marshaler for map value type main.NonMarshalable :: unhandled type: main.NonMarshalable
    }
    
    func main() {
        jsonEmptyMap()
        jsonNonEmptyMap()
        qsEmptyMap()
        qsTypeCheck()
    }