我想整理进出x-www-form-urlencoding,类似于你如何使用json或xml。是否有现成的软件包可以执行此操作,或者是否有任何文档如何在不存在的情况下自行实现?
答案 0 :(得分:14)
gorilla/schema受欢迎且维护良好:
e.g。
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也是另一种选择。
2015年5月23日更新:
我已经使用大猩猩/架构几年了,并且没有任何重大问题。我将它与vala结合使用,以便在它们命中数据库之前验证输入(不是零,太短,太长等)。
答案 1 :(得分:6)
我刚刚找到了https://github.com/ajg/form,这正是我想要的。还有https://github.com/gorilla/schema用于严格解码,https://github.com/google/go-querystring用于严格编码。
答案 2 :(得分:2)
https://github.com/google/go-querystring很好,但不支持地图(和地图切片)。
我开始https://github.com/drewlesueur/querystring以获取地图支持。 (它还不支持结构,但欢迎拉取请求。)
答案 3 :(得分:1)
The "github.com/pasztorpisti/qs"
package还可以将结构编组到/从查询字符串和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
)也可以替换编组程序和解组程序,并在不修改类型本身的情况下添加对新类型的支持(例如:添加编组和/或time.Time
的解组。 Here就是一个例子。req
选项添加到struct field标记中,以便在解组时使字段成为必需字段。请注意,这是相当验证而不是解组,golang库通常会在两者之间进行分离,但我发现这个选项非常有用,因为它经常需要,它很简单并且读取得很好。对于那些希望避免req
并在解组后单独进行验证的人:有一个nil
标记选项与默认opt
几乎相同(代表&#34) ;可选&#34;)除了当给定字段不在解组查询字符串中时它不初始化nil指针。这样验证器代码可以通过在解组后查找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()
}
答案 4 :(得分:1)
net/url
似乎处理得很好:
package main
import (
"fmt"
"net/url"
)
func main() {
{
m := url.Values{
"CR": {"\r"}, "LF": {"\n"},
}
s := m.Encode()
fmt.Println(s) // CR=%0D&LF=%0A
}
{
s := "CR=%0D&LF=%0A"
m, e := url.ParseQuery(s)
if e != nil {
panic(e)
}
fmt.Printf("%q\n", m) // map["CR":["\r"] "LF":["\n"]]
}
}