improve the route feature for ghttp.Server

This commit is contained in:
John
2020-06-03 00:09:51 +08:00
parent 269378aa0d
commit ef1d9a561c
9 changed files with 192 additions and 65 deletions

View File

@ -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 {

View File

@ -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)
}

View File

@ -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()
}

View File

@ -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()
}

View File

@ -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
<div align=center>

View File

@ -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 {

View File

@ -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

View File

@ -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()

View File

@ -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{