From ef1d9a561ce54d52b80e3d94340b36f330891432 Mon Sep 17 00:00:00 2001 From: John Date: Wed, 3 Jun 2020 00:09:51 +0800 Subject: [PATCH] improve the route feature for ghttp.Server --- .example/net/ghttp/client/upload/client.go | 22 ++++++++ .example/net/ghttp/client/upload/server.go | 2 +- .example/net/ghttp/server/object/user.go | 15 +++--- .example/other/test.go | 27 +++++----- README.MD | 6 +-- net/ghttp/ghttp_server_router.go | 58 +++++++++++--------- net/ghttp/ghttp_unit_param_struct_test.go | 61 ++++++++++++++++++++++ net/ghttp/ghttp_unit_router_basic_test.go | 25 ++++++++- util/gconv/gconv_z_unit_struct_test.go | 41 ++++++++++----- 9 files changed, 192 insertions(+), 65 deletions(-) diff --git a/.example/net/ghttp/client/upload/client.go b/.example/net/ghttp/client/upload/client.go index 0199e3441..a26548029 100644 --- a/.example/net/ghttp/client/upload/client.go +++ b/.example/net/ghttp/client/upload/client.go @@ -2,12 +2,34 @@ package main import ( "fmt" + "github.com/gogf/gf/frame/g" + "path/filepath" "github.com/gogf/gf/net/ghttp" "github.com/gogf/gf/os/glog" ) +func SendXmlFile(gameId int, areaName string, filePath string) error { + path := filepath.FromSlash(filePath) + fmt.Println(path) + data := g.Map{ + "gameName": gameId, + "area": areaName, + "file": "@file:" + path, + "contentType": "json", + } + if r, err := ghttp.Post("http://127.0.0.1:8199/upload", data); err != nil { + panic(err) + } else { + defer r.Close() + fmt.Println("ok") + } + return nil +} + func main() { + SendXmlFile(1, "xxx", "/Users/john/Workspace/Go/GOPATH/src/github.com/gogf/gf/.example/net/ghttp/server/session.go") + return path := "/home/john/Workspace/Go/github.com/gogf/gf/version.go" r, e := ghttp.Post("http://127.0.0.1:8199/upload", "upload-file=@file:"+path) if e != nil { diff --git a/.example/net/ghttp/client/upload/server.go b/.example/net/ghttp/client/upload/server.go index 482e1a7d6..26751703c 100644 --- a/.example/net/ghttp/client/upload/server.go +++ b/.example/net/ghttp/client/upload/server.go @@ -8,7 +8,7 @@ import ( // Upload uploads files to /tmp . func Upload(r *ghttp.Request) { saveDirPath := "/tmp/" - files := r.GetUploadFiles("upload-file") + files := r.GetUploadFiles("file") if _, err := files.Save(saveDirPath); err != nil { r.Response.WriteExit(err) } diff --git a/.example/net/ghttp/server/object/user.go b/.example/net/ghttp/server/object/user.go index 8bb926d68..28d76456e 100644 --- a/.example/net/ghttp/server/object/user.go +++ b/.example/net/ghttp/server/object/user.go @@ -5,21 +5,18 @@ import ( "github.com/gogf/gf/net/ghttp" ) -type User struct { -} +type User struct{} -func (c *User) Index(r *ghttp.Request) { - r.Response.Write("Index") -} - -// 不符合规范,不会被注册 -func (c *User) Test(r *ghttp.Request, value interface{}) { +func (c *User) Test(r *ghttp.Request) { r.Response.Write("Test") } func main() { s := g.Server() - s.BindObject("/user", new(User)) + u := new(User) + s.Group("/", func(group *ghttp.RouterGroup) { + group.GET("/db-{table}/{id}", u, "Test") + }) s.SetPort(8199) s.Run() } diff --git a/.example/other/test.go b/.example/other/test.go index f6e15be50..f590bf262 100644 --- a/.example/other/test.go +++ b/.example/other/test.go @@ -1,23 +1,20 @@ package main import ( - "fmt" - "github.com/gogf/gf/encoding/gjson" + "github.com/gogf/gf/frame/g" "github.com/gogf/gf/net/ghttp" - "github.com/gogf/gf/util/guid" ) -func CreateSessionId(r *ghttp.Request) string { - var ( - agent = r.UserAgent() - address = r.RemoteAddr - cookie = r.Header.Get("Cookie") - ) - return guid.S([]byte(agent), []byte(address), []byte(cookie)) -} func main() { - body := "{\"id\": 413231383385427875}" - if dat, err := gjson.DecodeToJson(body); err == nil { - fmt.Println(dat.MustToJsonString()) - } + s := g.Server() + s.BindHandler("POST:/login", func(r *ghttp.Request) { + r.Response.Write("login handler") + }) + s.Group("/", func(group *ghttp.RouterGroup) { + group.GET("/test", func(r *ghttp.Request) { + r.Response.Write("for authenticated handler testing") + }) + }) + s.SetPort(8199) + s.Run() } diff --git a/README.MD b/README.MD index d43448b79..641d4ea19 100644 --- a/README.MD +++ b/README.MD @@ -32,13 +32,13 @@ golang version >= 1.11 ``` # Packages -1. **Primary** +1. **Primary Package** The `gf` repository maintains some basic and most commonly used packages, keeping it as lightweight and simple as possible. -1. **Community** +1. **Community Package** - The community packages are contrinuted and maintained by community members, which are reposited in `gogf` organization. Some of the community packages are seperated from th `gf` repository, which are not of common usage or are with heavy dependecies. + The community packages are contributed and maintained by community members, which are stored in `gogf` organization. Some of the community packages are separated from the `gf` repository, which are not of common usage or are with heavy dependencies. # Architecture
diff --git a/net/ghttp/ghttp_server_router.go b/net/ghttp/ghttp_server_router.go index 00ff298f9..1c21d397a 100644 --- a/net/ghttp/ghttp_server_router.go +++ b/net/ghttp/ghttp_server_router.go @@ -230,12 +230,40 @@ func (s *Server) compareRouterPriority(newItem *handlerItem, oldItem *handlerIte if newItem.router.Priority < oldItem.router.Priority { return false } - // Route type: {xxx} > :xxx > *xxx. - // Eg: /name/act > /{name}/:act - var fuzzyCountFieldNew, fuzzyCountFieldOld int - var fuzzyCountNameNew, fuzzyCountNameOld int - var fuzzyCountAnyNew, fuzzyCountAnyOld int - var fuzzyCountTotalNew, fuzzyCountTotalOld int + + // Compare the length of their URI, + // but the fuzzy and named parts of the URI are not calculated to the result. + + // Eg: + // /admin-goods-{page} > /admin-{page} + // /{hash}.{type} > /{hash} + var uriNew, uriOld string + uriNew, _ = gregex.ReplaceString(`\{[^/]+?\}`, "", newItem.router.Uri) + uriOld, _ = gregex.ReplaceString(`\{[^/]+?\}`, "", oldItem.router.Uri) + uriNew, _ = gregex.ReplaceString(`:[^/]+?`, "", uriNew) + uriOld, _ = gregex.ReplaceString(`:[^/]+?`, "", uriOld) + uriNew, _ = gregex.ReplaceString(`\*[^/]*`, "", uriNew) // Replace "/*" and "/*any". + uriOld, _ = gregex.ReplaceString(`\*[^/]*`, "", uriOld) // Replace "/*" and "/*any". + if len(uriNew) > len(uriOld) { + return true + } + if len(uriNew) < len(uriOld) { + return false + } + + // Route type checks: {xxx} > :xxx > *xxx. + // Eg: + // /name/act > /{name}/:act + var ( + fuzzyCountFieldNew int + fuzzyCountFieldOld int + fuzzyCountNameNew int + fuzzyCountNameOld int + fuzzyCountAnyNew int + fuzzyCountAnyOld int + fuzzyCountTotalNew int + fuzzyCountTotalOld int + ) for _, v := range newItem.router.Uri { switch v { case '{': @@ -282,24 +310,6 @@ func (s *Server) compareRouterPriority(newItem *handlerItem, oldItem *handlerIte return false } - // It then compares the length of their URI, - // but the fuzzy and named parts of the URI are not calculated to the result. - - // Eg: /admin-goods-{page} > /admin-{page} - var uriNew, uriOld string - uriNew, _ = gregex.ReplaceString(`\{[^/]+\}`, "", newItem.router.Uri) - uriNew, _ = gregex.ReplaceString(`:[^/]+`, "", uriNew) - uriNew, _ = gregex.ReplaceString(`\*[^/]+`, "", uriNew) - uriOld, _ = gregex.ReplaceString(`\{[^/]+\}`, "", oldItem.router.Uri) - uriOld, _ = gregex.ReplaceString(`:[^/]+`, "", uriOld) - uriOld, _ = gregex.ReplaceString(`\*[^/]+`, "", uriOld) - if len(uriNew) > len(uriOld) { - return true - } - if len(uriNew) < len(uriOld) { - return false - } - // It then compares the accuracy of their http method, // the more accurate the more priority. if newItem.router.Method != gDEFAULT_METHOD { diff --git a/net/ghttp/ghttp_unit_param_struct_test.go b/net/ghttp/ghttp_unit_param_struct_test.go index cfd358c06..1d507b825 100644 --- a/net/ghttp/ghttp_unit_param_struct_test.go +++ b/net/ghttp/ghttp_unit_param_struct_test.go @@ -18,6 +18,67 @@ import ( "github.com/gogf/gf/test/gtest" ) +func Test_Params_Parse1(t *testing.T) { + type User struct { + Id int + Name string + Map map[string]interface{} + } + p, _ := ports.PopRand() + s := g.Server(p) + s.BindHandler("/parse", func(r *ghttp.Request) { + if m := r.GetMap(); len(m) > 0 { + var user *User + if err := r.Parse(&user); err != nil { + r.Response.WriteExit(err) + } + r.Response.WriteExit(user.Map["id"], user.Map["score"]) + } + }) + s.SetPort(p) + s.SetDumpRouterMap(false) + s.Start() + defer s.Shutdown() + + time.Sleep(100 * time.Millisecond) + gtest.C(t, func(t *gtest.T) { + client := ghttp.NewClient() + client.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", p)) + t.Assert(client.PostContent("/parse", `{"id":1,"name":"john","map":{"id":1,"score":100}}`), `1100`) + }) +} + +// It does not support this kind of converting yet. +//func Test_Params_Parse2(t *testing.T) { +// type User struct { +// Id int +// Name string +// Scores [][]int +// } +// p, _ := ports.PopRand() +// s := g.Server(p) +// s.BindHandler("/parse", func(r *ghttp.Request) { +// if m := r.GetMap(); len(m) > 0 { +// var user *User +// if err := r.Parse(&user); err != nil { +// r.Response.WriteExit(err) +// } +// r.Response.WriteExit(user.Scores) +// } +// }) +// s.SetPort(p) +// s.SetDumpRouterMap(false) +// s.Start() +// defer s.Shutdown() +// +// time.Sleep(100 * time.Millisecond) +// gtest.C(t, func(t *gtest.T) { +// client := ghttp.NewClient() +// client.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", p)) +// t.Assert(client.PostContent("/parse", `{"id":1,"name":"john","scores":[[1,2,3]]}`), `1100`) +// }) +//} + func Test_Params_Struct(t *testing.T) { type User struct { Id int diff --git a/net/ghttp/ghttp_unit_router_basic_test.go b/net/ghttp/ghttp_unit_router_basic_test.go index f034d3359..2b43dd775 100644 --- a/net/ghttp/ghttp_unit_router_basic_test.go +++ b/net/ghttp/ghttp_unit_router_basic_test.go @@ -16,7 +16,7 @@ import ( "github.com/gogf/gf/test/gtest" ) -func Test_Router_Basic(t *testing.T) { +func Test_Router_Basic1(t *testing.T) { p, _ := ports.PopRand() s := g.Server(p) s.BindHandler("/:name", func(r *ghttp.Request) { @@ -50,6 +50,29 @@ func Test_Router_Basic(t *testing.T) { }) } +func Test_Router_Basic2(t *testing.T) { + p, _ := ports.PopRand() + s := g.Server(p) + s.BindHandler("/{hash}", func(r *ghttp.Request) { + r.Response.Write(r.Get("hash")) + }) + s.BindHandler("/{hash}.{type}", func(r *ghttp.Request) { + r.Response.Write(r.Get("type")) + }) + s.SetPort(p) + s.SetDumpRouterMap(false) + s.Start() + defer s.Shutdown() + + time.Sleep(100 * time.Millisecond) + gtest.C(t, func(t *gtest.T) { + client := ghttp.NewClient() + client.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", p)) + t.Assert(client.GetContent("/data"), "data") + t.Assert(client.GetContent("/data.json"), "json") + }) +} + // HTTP method register. func Test_Router_Method(t *testing.T) { p, _ := ports.PopRand() diff --git a/util/gconv/gconv_z_unit_struct_test.go b/util/gconv/gconv_z_unit_struct_test.go index a16dd2be3..cb3300eb1 100644 --- a/util/gconv/gconv_z_unit_struct_test.go +++ b/util/gconv/gconv_z_unit_struct_test.go @@ -38,7 +38,7 @@ func Test_Struct_Basic1(t *testing.T) { "PASS2": "456", } if err := gconv.Struct(params1, user); err != nil { - gtest.Error(err) + t.Error(err) } t.Assert(user, &User{ Uid: 1, @@ -60,7 +60,7 @@ func Test_Struct_Basic1(t *testing.T) { "password2": "222", } if err := gconv.Struct(params2, user); err != nil { - gtest.Error(err) + t.Error(err) } t.Assert(user, &User{ Uid: 2, @@ -92,7 +92,7 @@ func Test_Struct_Basic2(t *testing.T) { "PASS2": "456", } if err := gconv.Struct(params, user); err != nil { - gtest.Error(err) + t.Error(err) } t.Assert(user, &User{ Uid: 1, @@ -117,15 +117,14 @@ func Test_Struct_Basic3(t *testing.T) { "Name": "john", } if err := gconv.Struct(params, user); err != nil { - gtest.Error(err) + t.Error(err) } t.Assert(user.Uid, 1) t.Assert(*user.Name, "john") }) } -// slice类型属性的赋值 -func Test_Struct_Attr_Slice(t *testing.T) { +func Test_Struct_Attr_Slice1(t *testing.T) { gtest.C(t, func(t *gtest.T) { type User struct { Scores []int @@ -133,7 +132,7 @@ func Test_Struct_Attr_Slice(t *testing.T) { scores := []interface{}{99, 100, 60, 140} user := new(User) if err := gconv.Struct(g.Map{"Scores": scores}, user); err != nil { - gtest.Error(err) + t.Error(err) } else { t.Assert(user, &User{ Scores: []int{99, 100, 60, 140}, @@ -142,6 +141,24 @@ func Test_Struct_Attr_Slice(t *testing.T) { }) } +// It does not support this kind of converting yet. +//func Test_Struct_Attr_Slice2(t *testing.T) { +// gtest.C(t, func(t *gtest.T) { +// type User struct { +// Scores [][]int +// } +// scores := []interface{}{[]interface{}{99, 100, 60, 140}} +// user := new(User) +// if err := gconv.Struct(g.Map{"Scores": scores}, user); err != nil { +// t.Error(err) +// } else { +// t.Assert(user, &User{ +// Scores: [][]int{{99, 100, 60, 140}}, +// }) +// } +// }) +//} + // 属性为struct对象 func Test_Struct_Attr_Struct(t *testing.T) { gtest.C(t, func(t *gtest.T) { @@ -163,7 +180,7 @@ func Test_Struct_Attr_Struct(t *testing.T) { // 嵌套struct转换 if err := gconv.Struct(scores, user); err != nil { - gtest.Error(err) + t.Error(err) } else { t.Assert(user, &User{ Scores: Score{ @@ -196,7 +213,7 @@ func Test_Struct_Attr_Struct_Ptr(t *testing.T) { // 嵌套struct转换 if err := gconv.Struct(scores, user); err != nil { - gtest.Error(err) + t.Error(err) } else { t.Assert(user.Scores, &Score{ Name: "john", @@ -227,7 +244,7 @@ func Test_Struct_Attr_Struct_Slice1(t *testing.T) { // 嵌套struct转换,属性为slice类型,数值为map类型 if err := gconv.Struct(scores, user); err != nil { - gtest.Error(err) + t.Error(err) } else { t.Assert(user.Scores, []Score{ { @@ -266,7 +283,7 @@ func Test_Struct_Attr_Struct_Slice2(t *testing.T) { // 嵌套struct转换,属性为slice类型,数值为slice map类型 if err := gconv.Struct(scores, user); err != nil { - gtest.Error(err) + t.Error(err) } else { t.Assert(user.Scores, []Score{ { @@ -309,7 +326,7 @@ func Test_Struct_Attr_Struct_Slice_Ptr(t *testing.T) { // 嵌套struct转换,属性为slice类型,数值为slice map类型 if err := gconv.Struct(scores, user); err != nil { - gtest.Error(err) + t.Error(err) } else { t.Assert(len(user.Scores), 2) t.Assert(user.Scores[0], &Score{