Go学习笔记(十):构建Restful服务
2020-05-09 17:30:49json解析
内置json解析
利⽤反射实现,通过FeildTag来标识对应的json 值
type BasicInfo struct {
Name string `json:"name"`
Age int `json:"age"`
}
type JobInfo struct {
Skills []string `json:"skills"`
}
type Employee struct {
BasicInfo BasicInfo `json:"basic_info"`
JobInfo JobInfo `json:"job_info"`
}
var jsonStr = `{
"basic_info":{
"name":"Mike",
"age":30
},
"job_info":{
"skills":["Java","Go","C"]
}
} `
func TestEmbeddedJson(t *testing.T) {
e := new(Employee)
err := json.Unmarshal([]byte(jsonStr), e)
if err != nil {
t.Error(err)
}
fmt.Println(*e)
if v, err := json.Marshal(e); err == nil {
fmt.Println(string(v))
} else {
t.Error(err)
}
}
更快的JSON解析
EasyJSON 采用代码生成而非反射
安装:go get -u github.com/mailru/easyjson/... (后面的...需要带上)
使⽤:easyjson -all <结构定义>.go (会生成一些代码)
1.比如我们有结构文件 struct_def.go
type BasicInfo struct {
Name string
Age int
}
type JobInfo struct {
Skills []string
}
type Employee struct {
BasicInfo BasicInfo
JobInfo JobInfo
}
2.执行 easyjson -all struct_def.go会生成 struct_def_easyjson.go文件(这个文件的代码就不贴出来了)
3.测试解析
var jsonStr = `{
"basic_info":{
"name":"Mike",
"age":30
},
"job_info":{
"skills":["Java","Go","C"]
}
} `
func TestEmbeddedJson(t *testing.T) {
e := new(Employee)
err := json.Unmarshal([]byte(jsonStr), e)
if err != nil {
t.Error(err)
}
fmt.Println(*e)
if v, err := json.Marshal(e); err == nil {
fmt.Println(string(v))
} else {
t.Error(err)
}
}
func TestEasyJson(t *testing.T) {
e := Employee{}
e.UnmarshalJSON([]byte(jsonStr))
fmt.Println(e)
if v, err := e.MarshalJSON(); err != nil {
t.Error(err)
} else {
fmt.Println(string(v))
}
}
func BenchmarkEmbeddedJson(b *testing.B) {
b.ResetTimer()
e := new(Employee)
for i := 0; i < b.N; i++ {
err := json.Unmarshal([]byte(jsonStr), e)
if err != nil {
b.Error(err)
}
if _, err = json.Marshal(e); err != nil {
b.Error(err)
}
}
}
func BenchmarkEasyJson(b *testing.B) {
b.ResetTimer()
e := Employee{}
for i := 0; i < b.N; i++ {
err := e.UnmarshalJSON([]byte(jsonStr))
if err != nil {
b.Error(err)
}
if _, err = e.MarshalJSON(); err != nil {
b.Error(err)
}
}
}
HTTP服务
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello World!")
})
http.HandleFunc("/time/", func(w http.ResponseWriter, r *http.Request) {
t := time.Now()
timeStr := fmt.Sprintf("{\"time\": \"%s\"}", t)
w.Write([]byte(timeStr))
})
http.ListenAndServe(":8080", nil)
}
路由规则
- URL 分为两种,末尾是 /:表示⼀个⼦树,后⾯可以跟其他⼦路径;末尾不是 /,表示⼀个叶⼦,固定的路径
- 以/ 结尾的 URL 可以匹配它的任何⼦路径,⽐如 /images 会匹配 /images/cute-cat.jpg
- 它采⽤最⻓匹配原则,如果有多个匹配,⼀定采⽤匹配路径最⻓的那个进⾏处理
- 如果没有找到任何匹配项,会返回 404 错误
更好的Router
https://github.com/julienschmidt/httprouter
import (
"fmt"
"log"
"net/http"
"github.com/julienschmidt/httprouter"
)
func Index(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
fmt.Fprint(w, "Welcome!\n")
}
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("/", Index)
router.GET("/hello/:name", Hello)
log.Fatal(http.ListenAndServe(":8080", router))
}
面向资源的架构(Resource Oriented Architecture)
roa实例
import (
"encoding/json"
"fmt"
"log"
"net/http"
"github.com/julienschmidt/httprouter"
)
type Employee struct {
ID string `json:"id"`
Name string `json:"name"`
Age int `json:"age"`
}
var employeeDB map[string]*Employee
func init() {
employeeDB = map[string]*Employee{}
employeeDB["Mike"] = &Employee{"e-1", "Mike", 35}
employeeDB["Rose"] = &Employee{"e-2", "Rose", 45}
}
func Index(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
fmt.Fprint(w, "Welcome!\n")
}
func GetEmployeeByName(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
qName := ps.ByName("name")
var (
ok bool
info *Employee
infoJson []byte
err error
)
if info, ok = employeeDB[qName]; !ok {
w.Write([]byte("{\"error\":\"Not Found\"}"))
return
}
if infoJson, err = json.Marshal(info); err != nil {
w.Write([]byte(fmt.Sprintf("{\"error\":,\"%s\"}", err)))
return
}
w.Write(infoJson)
}
func main() {
router := httprouter.New()
router.GET("/", Index)
router.GET("/employee/:name", GetEmployeeByName)
log.Fatal(http.ListenAndServe(":8080", router))
}