Go 每日一庫之 gorilla-schema
簡介
gorilla/schema
是 gorilla 開發工具包中用於處理表單的庫。它提供了一個簡單的方式,可以很方便地將表單數據轉爲結構體對象,或者將結構體對象轉爲表單數據。
快速使用
本文代碼使用 Go Modules。
創建目錄並初始化:
$ mkdir gorilla/schema && cd gorilla/schema
$ go mod init github.com/darjun/go-daily-lib/gorilla/schema
安裝gorilla/schema
庫:
$ go get -u github.com/gorilla/schema
我們還是拿前面登錄的例子:
func index(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Hello World")
}
func login(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta >
<title>Login</title>
</head>
<body>
<form action="/login" method="post">
<label>Username:</label>
<input ><br>
<label>Password:</label>
<input ><br>
<button type="submit">登錄</button>
</form>
</body>
</html>`)
}
type User struct {
Username string `schema:"username"`
Password string `schema:"password"`
}
var (
decoder = schema.NewDecoder()
)
func dologin(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
u := User{}
decoder.Decode(&u, r.PostForm)
if u.Username == "dj" && u.Password == "handsome" {
http.Redirect(w, r, "/", 301)
return
}
http.Redirect(w, r, "/login", 301)
}
func main() {
r := mux.NewRouter()
r.HandleFunc("/", index)
r.Handle("/login", handlers.MethodHandler{
"GET": http.HandlerFunc(login),
"POST": http.HandlerFunc(dologin),
})
log.Fatal(http.ListenAndServe(":8080", r))
}
首先調用schema.NewDecoder()
方法創建一個解碼器decoder
。在處理器中,先調用r.ParseForm()
解析表單數據,然後創建用戶對象u
,調用decoder.Decode(&u, r.PostForm)
通過表單數據填充該對象。
schema
使用反射來對應表單和結構體字段,我們可以通過結構體標籤來指定表單數據和字段的對應關係。
上面我們將解碼器作爲一個包內的全局變量,因爲decoder
中會緩存一些結構體的元數據,並且它是併發安全的。
在main
函數中,我們創建了gorilla/mux
路由,註冊/
根處理函數,使用中間件handlers.MethodHandler
分別註冊路徑/login
的 GET 和 POST 方法的處理器。然後調用http.Handle("/", r)
將所有請求交由gorilla/mux
路由處理。最後啓動 Web 服務器接受請求。
編碼
除了用於服務器解碼錶單數據外,schema
還可用於客戶端,將結構體對象編碼到表單數據中發送給服務器。我們編寫一個程序登錄上面的服務器:
var (
encoder = schema.NewEncoder()
)
func main() {
client := &http.Client{}
form := url.Values{}
u := &User{
Username: "dj",
Password: "handsome",
}
encoder.Encode(u, form)
res, _ := client.PostForm("http://localhost:8080/login", form)
data, _ := ioutil.ReadAll(res.Body)
fmt.Println(string(data))
res.Body.Close()
}
與解碼器的用法類似,首先調用schema.NewEncoder()
創建一個編碼器encoder
,創建一個User
類型的對象u
和表單數據對象form
,調用encoder.Encode(u, form)
將u
編碼到form
中。然後使用http.Client
的PostForm
方法發送請求。讀取響應。
自定義類型轉換
目前schema
支持以下類型:
-
布爾類型:
bool
-
浮點數:
float32/float64
-
有符號整數:
int/int8/int32/int64
-
無符號整數:
uint/uint8/uint32/uint64
-
字符串:
string
-
結構體:由以上類型組成的結構體
-
指針:指向以上類型的指針
-
切片:元素爲以上類型的切片,或指向切片的指針
有時候客戶端會將一個切片拼成一個字符串傳到服務器,服務器收到之後需要解析成切片:
type Person struct {
Name string `schema:"name"`
Age int `schema:"age"`
Hobbies []string `schema:"hobbies"`
}
var (
decoder = schema.NewDecoder()
)
func init() {
decoder.RegisterConverter([]string{}, func(s string) reflect.Value {
return reflect.ValueOf(strings.Split(s, ","))
})
}
func doinfo(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
p := Person{}
decoder.Decode(&p, r.PostForm)
fmt.Println(p)
fmt.Fprintf(w, "Name:%s Age:%d Hobbies:%v", p.Name, p.Age, p.Hobbies)
}
調用decoder.RegisterConverter()
註冊對應類型的轉換函數,轉換函數類型爲:
func(s string) reflect.Value
即將請求中的字符串值轉爲滿足我們格式的值。
客戶端請求:
type Person struct {
Name string `schema:"name"`
Age int `schema:"age"`
Hobbies string `schema:"hobbies"`
}
var (
encoder = schema.NewEncoder()
)
func main() {
client := &http.Client{}
form := url.Values{}
p := &Person{
Name: "dj",
Age: 18,
Hobbies: "Game,Programming",
}
encoder.Encode(p, form)
res, _ := client.PostForm("http://localhost:8080/info", form)
data, _ := ioutil.ReadAll(res.Body)
fmt.Println(string(data))
res.Body.Close()
}
客戶端故意將Hobbies
字段設置爲字符串,發送請求。服務器將使用註冊的func (s string) reflect.Value
函數將該字符串切割爲[]string
返回。
總結
schema
提供了一個簡單的獲取表單數據的方式,通過將數據填充到結構體對象中,我們可以很方便的進行後續操作。schema
庫比較小巧,對特性沒太多要求的可以試試~
大家如果發現好玩、好用的 Go 語言庫,歡迎到 Go 每日一庫 GitHub 上提交 issue😄
參考
-
gorilla/schema GitHub:github.com/gorilla/schema
-
Go 每日一庫 GitHub:https://github.com/darjun/go-daily-lib
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/88WNqhxq6RacbK2Ev9JDTg