golang:解析HTTP请求参数
《GO程序设计语⾔》设计中案例,仅作为笔记进⾏收藏。此案例将HTTP请求参数解析成对应的匿名结构体,并使⽤反射来获取字段标签。
params 解析函数
package params
import (
"fmt"
"net/http"党员转正
"reflect"
"strconv"
"strings"
)
// Unpack 从 HTTP 请求 req 的参数中提取数据填充到 ptr 指向结构体的各个字段
func Unpack(req *http.Request, ptr interface{}) error {
if err := req.ParForm(); err != nil {
return err
}
// 创建字段映射表,键为有效名称
fields := make(map[string]reflect.Value)
v := reflect.ValueOf(ptr).Elem()
for i := 0; i < v.NumField(); i++ {
fieldInfo := v.Type().Field(i)
tag := fieldInfo.Tag
name := tag.Get("http")
if name == "" {
name = strings.ToLower(fieldInfo.Name)
}
fields[name] = v.Field(i)
}
// 对请求中的每个参数更新结构体中对应的字段
for name, values := range req.Form {
f := fields[name]
if !f.IsValid() {
又见明月
continue // 忽略不能识别的 HTTP 参数
}
for _, value := range values {
if f.Kind() == reflect.Slice {
elem := reflect.New(f.Type().Elem()).Elem()
if err := populate(elem, value); err != nil {
赵传return fmt.Errorf("%s: %v", name, err)
}
f.Set(reflect.Append(f, elem))
} el {
if err := populate(f, value); err != nil {
return fmt.Errorf("%s: %v", name, err)
}
}
}
}
return nil
}
func populate(v reflect.Value, value string) error {
儿白switch v.Kind() {
ca reflect.String:
v.SetString(value)
v.SetString(value)
ca reflect.Int:
亡羊补牢近义词
i, err := strconv.ParInt(value, 10, 64)
if err != nil {
return err
}
v.SetInt(i)
ca reflect.Bool:
b, err := strconv.ParBool(value)
贴对联的讲究if err != nil {
return err
}
v.SetBool(b)
default:
return fmt.Errorf("unsupported kind %s", v.Type())
}
return nil
}
arch 请求
package main
import (
"fmt"
"log"
"net/http"
"main/params"
)
func arch(resp http.ResponWriter, req *http.Request) { var data struct {
Labels []string `http:"l"`
MaxResults int `http:"max"`
Exact bool `http:"x"`
}
// 设置默认值
data.MaxResults = 10
if err := params.Unpack(req, &data); err != nil {
http.Error(resp, err.Error(), http.StatusBadRequest)
return
}
fmt.Fprintf(resp, "Search:%+v\n", data)
}
可乐排骨的做法hp工作站func main() {
http.HandleFunc("/arch", arch)
log.Fatal(http.ListenAndServe(":8080", nil))
}