mirror of
https://gitee.com/johng/gf
synced 2026-06-06 02:25:47 +08:00
add middleware feature for ghttp.Server
This commit is contained in:
50
.example/database/gdb/mysql/gdb_issue_278.go
Normal file
50
.example/database/gdb/mysql/gdb_issue_278.go
Normal file
@ -0,0 +1,50 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/gogf/gf/frame/g"
|
||||
)
|
||||
|
||||
var (
|
||||
tableName = "orders"
|
||||
dao = g.DB().Table(tableName).Safe()
|
||||
)
|
||||
|
||||
type OrderServiceEntity struct {
|
||||
GoodsPrice float64 `json:"goods_price" gvalid:"required"`
|
||||
PayTo int8 `json:"payTo" gvalid:"required"`
|
||||
PayStatus int8 `json:"payStatus" `
|
||||
CreateTime string `json:"createTime" `
|
||||
AppId string `json:"appId" gvalid:"required"`
|
||||
PayUser string `json:"pay_user" gvalid:"required"`
|
||||
QrUrl string `json:"qr_url" `
|
||||
}
|
||||
|
||||
type Create struct {
|
||||
Id int64 `json:"id" gconv:"id"`
|
||||
GoodsPrice float64 `json:"goodsPrice" gconv:"goods_price"`
|
||||
PayTo int8 `json:"payTo" gconv:"pay_to"`
|
||||
PayStatus int8 `json:"payStatus" gconv:"pay_status"`
|
||||
CreateTime string `json:"createTime" gconv:"create_time"`
|
||||
UserId int `json:"user_id" `
|
||||
PayUser string `json:"pay_user" `
|
||||
QrUrl string `json:"qr_url" `
|
||||
}
|
||||
|
||||
func main() {
|
||||
g.DB().SetDebug(true)
|
||||
userInfo := Create{
|
||||
Id: 3,
|
||||
}
|
||||
orderService := OrderServiceEntity{
|
||||
GoodsPrice: 0.1,
|
||||
PayTo: 1,
|
||||
}
|
||||
size, err := dao.Where("user_id", userInfo.Id).
|
||||
And("goods_price", float64(100.10)).
|
||||
And("pay_status", 0).
|
||||
And("pay_to", orderService.PayTo).Count()
|
||||
fmt.Println(err)
|
||||
fmt.Println(size)
|
||||
}
|
||||
@ -36,3 +36,20 @@ func BuildParams(params interface{}, noUrlEncode ...bool) (encodedParamStr strin
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 友好地调用方法
|
||||
func niceCallFunc(f func()) {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
switch err {
|
||||
case gEXCEPTION_EXIT:
|
||||
fallthrough
|
||||
case gEXCEPTION_EXIT_ALL:
|
||||
return
|
||||
default:
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
f()
|
||||
}
|
||||
|
||||
@ -21,12 +21,7 @@ import (
|
||||
// 请求对象
|
||||
type Request struct {
|
||||
*http.Request
|
||||
parsedGet bool // GET参数是否已经解析
|
||||
parsedPost bool // POST参数是否已经解析
|
||||
queryVars map[string][]string // GET参数
|
||||
routerVars map[string][]string // 路由解析参数
|
||||
exit bool // 是否退出当前请求流程执行
|
||||
Id int // 请求id(唯一)
|
||||
Id int // 请求ID(当前Server对象唯一)
|
||||
Server *Server // 请求关联的服务器对象
|
||||
Cookie *Cookie // 与当前请求绑定的Cookie对象(并发安全)
|
||||
Session *Session // 与当前请求绑定的Session对象(并发安全)
|
||||
@ -34,6 +29,14 @@ type Request struct {
|
||||
Router *Router // 匹配到的路由对象
|
||||
EnterTime int64 // 请求进入时间(微秒)
|
||||
LeaveTime int64 // 请求完成时间(微秒)
|
||||
MiddleWare *MiddleWare // 中间件功能调用对象
|
||||
handlers []*handlerParsedItem // 请求执行服务函数列表(包含中间件、路由函数、钩子函数)
|
||||
handlerIndex int // 当前执行函数的索引号
|
||||
parsedGet bool // GET参数是否已经解析
|
||||
parsedPost bool // POST参数是否已经解析
|
||||
queryVars map[string][]string // GET参数
|
||||
routerVars map[string][]string // 路由解析参数
|
||||
exit bool // 是否退出当前请求流程执行
|
||||
params map[string]interface{} // 开发者自定义参数(请求流程中有效)
|
||||
parsedHost string // 解析过后不带端口号的服务器域名名称
|
||||
clientIp string // 解析过后的客户端IP地址
|
||||
@ -55,6 +58,9 @@ func newRequest(s *Server, r *http.Request, w http.ResponseWriter) *Request {
|
||||
request.Cookie = GetCookie(request)
|
||||
request.Session = GetSession(request)
|
||||
request.Response.request = request
|
||||
request.MiddleWare = &MiddleWare{
|
||||
request: request,
|
||||
}
|
||||
return request
|
||||
}
|
||||
|
||||
|
||||
77
net/ghttp/ghttp_request_middleware.go
Normal file
77
net/ghttp/ghttp_request_middleware.go
Normal file
@ -0,0 +1,77 @@
|
||||
// Copyright 2017 gf Author(https://github.com/gogf/gf). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package ghttp
|
||||
|
||||
import "reflect"
|
||||
|
||||
// 中间件对象
|
||||
type MiddleWare struct {
|
||||
request *Request
|
||||
}
|
||||
|
||||
// 执行下一个请求流程处理函数
|
||||
func (m *MiddleWare) Next() {
|
||||
item := (*handlerParsedItem)(nil)
|
||||
for ; m.request.handlerIndex < len(m.request.handlers); m.request.handlerIndex++ {
|
||||
// 是否停止请求执行
|
||||
if m.request.IsExited() {
|
||||
return
|
||||
}
|
||||
item = m.request.handlers[m.request.handlerIndex]
|
||||
// 通过中间件模式不执行钩子函数
|
||||
if item.handler.itemType == gHANDLER_TYPE_HOOK {
|
||||
continue
|
||||
}
|
||||
// 路由参数赋值
|
||||
for k, v := range item.values {
|
||||
m.request.routerVars[k] = v
|
||||
}
|
||||
m.request.Router = item.handler.router
|
||||
// 执行函数处理
|
||||
switch item.handler.itemType {
|
||||
case gHANDLER_TYPE_CONTROLLER:
|
||||
c := reflect.New(item.handler.ctrlInfo.reflect)
|
||||
niceCallFunc(func() {
|
||||
c.MethodByName("Init").Call([]reflect.Value{reflect.ValueOf(m.request)})
|
||||
})
|
||||
if m.request.IsExited() {
|
||||
niceCallFunc(func() {
|
||||
c.MethodByName(item.handler.ctrlInfo.name).Call(nil)
|
||||
})
|
||||
}
|
||||
if m.request.IsExited() {
|
||||
niceCallFunc(func() {
|
||||
c.MethodByName("Shut").Call(nil)
|
||||
})
|
||||
}
|
||||
case gHANDLER_TYPE_OBJECT:
|
||||
if item.handler.initFunc != nil {
|
||||
niceCallFunc(func() {
|
||||
item.handler.initFunc(m.request)
|
||||
})
|
||||
}
|
||||
if m.request.IsExited() {
|
||||
niceCallFunc(func() {
|
||||
item.handler.itemFunc(m.request)
|
||||
})
|
||||
}
|
||||
if m.request.IsExited() && item.handler.shutFunc != nil {
|
||||
niceCallFunc(func() {
|
||||
item.handler.shutFunc(m.request)
|
||||
})
|
||||
}
|
||||
case gHANDLER_TYPE_HANDLER:
|
||||
niceCallFunc(func() {
|
||||
item.handler.itemFunc(m.request)
|
||||
})
|
||||
case gHANDLER_TYPE_MIDDLEWARE:
|
||||
niceCallFunc(func() {
|
||||
item.handler.itemFunc(m.request)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -137,7 +137,7 @@ func (r *Response) WriteStatus(status int, content ...interface{}) {
|
||||
// 状态码注册回调函数处理
|
||||
if status != http.StatusOK {
|
||||
if f := r.request.Server.getStatusHandler(status, r.request); f != nil {
|
||||
r.Server.niceCallFunc(func() {
|
||||
niceCallFunc(func() {
|
||||
f(r.request)
|
||||
})
|
||||
// 防止多次设置(http: multiple response.WriteHeader calls)
|
||||
|
||||
@ -1,70 +0,0 @@
|
||||
// Copyright 2017 gf Author(https://github.com/gogf/gf). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
//
|
||||
|
||||
package ghttp
|
||||
|
||||
// 默认的gzip压缩文件类型
|
||||
var defaultGzipContentTypes = []string{
|
||||
"application/atom+xml",
|
||||
"application/font-sfnt",
|
||||
"application/javascript",
|
||||
"application/json",
|
||||
"application/ld+json",
|
||||
"application/manifest+json",
|
||||
"application/rdf+xml",
|
||||
"application/rss+xml",
|
||||
"application/schema+json",
|
||||
"application/vnd.geo+json",
|
||||
"application/vnd.ms-fontobject",
|
||||
"application/x-font-ttf",
|
||||
"application/x-javascript",
|
||||
"application/x-web-app-manifest+json",
|
||||
"application/xhtml+xml",
|
||||
"application/xml",
|
||||
"font/eot",
|
||||
"font/opentype",
|
||||
"image/bmp",
|
||||
"image/svg+xml",
|
||||
"image/vnd.microsoft.icon",
|
||||
"image/x-icon",
|
||||
"text/cache-manifest",
|
||||
"text/css",
|
||||
"text/html",
|
||||
"text/javascript",
|
||||
"text/plain",
|
||||
"text/vcard",
|
||||
"text/vnd.rim.location.xloc",
|
||||
"text/vtt",
|
||||
"text/x-component",
|
||||
"text/x-cross-domain-policy",
|
||||
"text/xml",
|
||||
}
|
||||
|
||||
//// 返回内容gzip检查处理
|
||||
//func (r *Response) handleGzip() {
|
||||
// // 如果客户端支持gzip压缩,并且服务端设置开启gzip压缩特性,那么执行压缩
|
||||
// encoding := r.request.Header.Get("Accept-Encoding")
|
||||
// if encoding != "" && strings.Contains(encoding, "gzip") {
|
||||
// mimeType := ""
|
||||
// ext := gfile.Ext(r.request.URL.Path)
|
||||
// if ext != "" {
|
||||
// mimeType = strings.Split(mime.TypeByExtension(ext), ";")[0]
|
||||
// }
|
||||
// if mimeType == "" {
|
||||
// contentType := r.Header().Get("Content-Type")
|
||||
// if contentType != "" {
|
||||
// mimeType = strings.Split(contentType, ";")[0]
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if _, ok := r.Server.gzipMimesMap[mimeType]; ok {
|
||||
// r.SetBuffer(gcompress.Gzip(r.buffer))
|
||||
// r.Header().Set("Content-Length", gconv.String(len(r.buffer)))
|
||||
// r.Header().Set("Content-Encoding", "gzip")
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
@ -15,7 +15,6 @@ import (
|
||||
"reflect"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/container/garray"
|
||||
@ -44,10 +43,10 @@ type (
|
||||
servedCount *gtype.Int // 已经服务的请求数(4-8字节,不考虑溢出情况),同时作为请求ID
|
||||
serveTree map[string]interface{} // 所有注册的服务回调函数(路由表,树型结构,哈希表+链表优先级匹配)
|
||||
hooksTree map[string]interface{} // 所有注册的事件回调函数(路由表,树型结构,哈希表+链表优先级匹配)
|
||||
middlewareTree map[string]interface{} // 所有注册的中间件(路由表,树型结构,哈希表+链表优先级匹配)
|
||||
serveCache *gcache.Cache // 服务注册路由内存缓存
|
||||
hooksCache *gcache.Cache // 事件回调路由内存缓存
|
||||
routesMap map[string][]registeredRouteItem // 已经注册的路由及对应的注册方法文件地址(用以路由重复注册判断)
|
||||
statusHandlerMu sync.RWMutex // status handler互斥锁
|
||||
statusHandlerMap map[string]HandlerFunc // 不同状态码下的注册处理方法(例如404状态时的处理方法)
|
||||
sessions *gcache.Cache // Session内存缓存
|
||||
logger *glog.Logger // 日志管理对象
|
||||
@ -63,16 +62,15 @@ type (
|
||||
Priority int // 优先级,用于链表排序,值越大优先级越高
|
||||
}
|
||||
|
||||
// http回调函数注册信息
|
||||
// 服务函数注册信息
|
||||
handlerItem struct {
|
||||
name string // 注册的方法名称信息
|
||||
rtype int // 注册方式(执行对象/回调函数/控制器)
|
||||
ctype reflect.Type // 控制器类型(反射类型)
|
||||
fname string // 回调方法名称
|
||||
faddr HandlerFunc // 准确的执行方法内存地址(与以上两个参数二选一)
|
||||
finit HandlerFunc // 初始化请求回调方法(执行对象注册方式下有效)
|
||||
fshut HandlerFunc // 完成请求回调方法(执行对象注册方式下有效)
|
||||
router *Router // 注册时绑定的路由对象
|
||||
itemName string // 注册的函数名称信息(用于路由信息打印)
|
||||
itemType int // 注册函数类型(对象/函数/控制器/中间件)
|
||||
itemFunc HandlerFunc // 函数内存地址(与以上两个参数二选一)
|
||||
initFunc HandlerFunc // 初始化请求回调函数(对象注册方式下有效)
|
||||
shutFunc HandlerFunc // 完成请求回调函数(对象注册方式下有效)
|
||||
ctrlInfo *handlerController // 控制器服务函数反射信息
|
||||
router *Router // 注册时绑定的路由对象
|
||||
}
|
||||
|
||||
// 根据特定URL.Path解析后的路由检索结果项
|
||||
@ -81,6 +79,12 @@ type (
|
||||
values map[string][]string // 特定URL.Path的Router解析参数
|
||||
}
|
||||
|
||||
// 控制器服务函数反射信息
|
||||
handlerController struct {
|
||||
name string // 方法名称
|
||||
reflect reflect.Type // 控制器类型
|
||||
}
|
||||
|
||||
// 已注册的路由项
|
||||
registeredRouteItem struct {
|
||||
file string // 文件路径及行数地址
|
||||
@ -98,25 +102,24 @@ type (
|
||||
)
|
||||
|
||||
const (
|
||||
SERVER_STATUS_STOPPED = 0 // Server状态:停止
|
||||
SERVER_STATUS_RUNNING = 1 // Server状态:运行
|
||||
HOOK_BEFORE_SERVE = "BeforeServe" // 回调事件,在执行服务前
|
||||
HOOK_AFTER_SERVE = "AfterServe" // 回调事件,在执行服务后
|
||||
HOOK_BEFORE_OUTPUT = "BeforeOutput" // 回调事件,在输出结果前
|
||||
HOOK_AFTER_OUTPUT = "AfterOutput" // 回调事件,在输出结果后
|
||||
HOOK_BEFORE_CLOSE = "BeforeClose" // Deprecated.
|
||||
HOOK_AFTER_CLOSE = "AfterClose" // Deprecated.
|
||||
|
||||
HTTP_METHODS = "GET,PUT,POST,DELETE,PATCH,HEAD,CONNECT,OPTIONS,TRACE"
|
||||
gDEFAULT_SERVER = "default"
|
||||
gDEFAULT_DOMAIN = "default"
|
||||
gDEFAULT_METHOD = "ALL"
|
||||
gROUTE_REGISTER_HANDLER = 1
|
||||
gROUTE_REGISTER_OBJECT = 2
|
||||
gROUTE_REGISTER_CONTROLLER = 3
|
||||
gEXCEPTION_EXIT = "exit"
|
||||
gEXCEPTION_EXIT_ALL = "exit_all"
|
||||
gEXCEPTION_EXIT_HOOK = "exit_hook"
|
||||
SERVER_STATUS_STOPPED = 0 // Server状态:停止
|
||||
SERVER_STATUS_RUNNING = 1 // Server状态:运行
|
||||
HOOK_BEFORE_SERVE = "BeforeServe" // 回调事件,在执行服务前
|
||||
HOOK_AFTER_SERVE = "AfterServe" // 回调事件,在执行服务后
|
||||
HOOK_BEFORE_OUTPUT = "BeforeOutput" // 回调事件,在输出结果前
|
||||
HOOK_AFTER_OUTPUT = "AfterOutput" // 回调事件,在输出结果后
|
||||
HTTP_METHODS = "GET,PUT,POST,DELETE,PATCH,HEAD,CONNECT,OPTIONS,TRACE"
|
||||
gDEFAULT_SERVER = "default"
|
||||
gDEFAULT_DOMAIN = "default"
|
||||
gDEFAULT_METHOD = "ALL"
|
||||
gHANDLER_TYPE_HANDLER = 1
|
||||
gHANDLER_TYPE_OBJECT = 2
|
||||
gHANDLER_TYPE_CONTROLLER = 3
|
||||
gHANDLER_TYPE_MIDDLEWARE = 4
|
||||
gHANDLER_TYPE_HOOK = 5
|
||||
gEXCEPTION_EXIT = "exit"
|
||||
gEXCEPTION_EXIT_ALL = "exit_all"
|
||||
gEXCEPTION_EXIT_HOOK = "exit_hook"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -240,23 +243,6 @@ func (s *Server) Start() error {
|
||||
if s.config.Handler == nil {
|
||||
s.config.Handler = http.HandlerFunc(s.defaultHttpHandle)
|
||||
}
|
||||
// 不允许访问的路由注册(使用HOOK实现)
|
||||
// TODO 去掉HOOK的实现方式
|
||||
if s.config.DenyRoutes != nil {
|
||||
for _, v := range s.config.DenyRoutes {
|
||||
s.BindHookHandler(v, HOOK_BEFORE_SERVE, func(r *Request) {
|
||||
r.Response.WriteStatus(403)
|
||||
r.ExitAll()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// gzip压缩文件类型
|
||||
//if s.config.GzipContentTypes != nil {
|
||||
// for _, v := range s.config.GzipContentTypes {
|
||||
// s.gzipMimesMap[v] = struct{}{}
|
||||
// }
|
||||
//}
|
||||
|
||||
// 启动http server
|
||||
reloaded := false
|
||||
@ -323,7 +309,7 @@ func (s *Server) GetRouteMap() string {
|
||||
domain: array[4],
|
||||
method: array[2],
|
||||
route: array[3],
|
||||
handler: registeredItem.handler.name,
|
||||
handler: registeredItem.handler.itemName,
|
||||
priority: len(registeredItems) - index - 1,
|
||||
}
|
||||
if _, ok := m[item.domain]; !ok {
|
||||
@ -347,19 +333,19 @@ func (s *Server) GetRouteMap() string {
|
||||
m[item.domain].Add(item)
|
||||
}
|
||||
}
|
||||
addr := s.config.Addr
|
||||
itemFunc := s.config.Addr
|
||||
if s.config.HTTPSAddr != "" {
|
||||
if len(addr) > 0 {
|
||||
addr += ","
|
||||
if len(itemFunc) > 0 {
|
||||
itemFunc += ","
|
||||
}
|
||||
addr += "tls" + s.config.HTTPSAddr
|
||||
itemFunc += "tls" + s.config.HTTPSAddr
|
||||
}
|
||||
for _, a := range m {
|
||||
data := make([]string, 8)
|
||||
for _, v := range a.Slice() {
|
||||
item := v.(*tableItem)
|
||||
data[0] = s.name
|
||||
data[1] = addr
|
||||
data[1] = itemFunc
|
||||
data[2] = item.domain
|
||||
data[3] = item.method
|
||||
data[4] = gconv.String(len(strings.Split(item.route, "/")) - 1 + item.priority)
|
||||
@ -422,19 +408,19 @@ func (s *Server) startServer(fdMap listenerFdMap) {
|
||||
continue
|
||||
}
|
||||
fd := 0
|
||||
addr := v
|
||||
itemFunc := v
|
||||
array := strings.Split(v, "#")
|
||||
if len(array) > 1 {
|
||||
addr = array[0]
|
||||
itemFunc = array[0]
|
||||
// windows系统不支持文件描述符传递socket通信平滑交接,因此只能完整重启
|
||||
if runtime.GOOS != "windows" {
|
||||
fd = gconv.Int(array[1])
|
||||
}
|
||||
}
|
||||
if fd > 0 {
|
||||
s.servers = append(s.servers, s.newGracefulServer(addr, fd))
|
||||
s.servers = append(s.servers, s.newGracefulServer(itemFunc, fd))
|
||||
} else {
|
||||
s.servers = append(s.servers, s.newGracefulServer(addr))
|
||||
s.servers = append(s.servers, s.newGracefulServer(itemFunc))
|
||||
}
|
||||
s.servers[len(s.servers)-1].isHttps = true
|
||||
}
|
||||
@ -457,19 +443,19 @@ func (s *Server) startServer(fdMap listenerFdMap) {
|
||||
continue
|
||||
}
|
||||
fd := 0
|
||||
addr := v
|
||||
itemFunc := v
|
||||
array := strings.Split(v, "#")
|
||||
if len(array) > 1 {
|
||||
addr = array[0]
|
||||
itemFunc = array[0]
|
||||
// windows系统不支持文件描述符传递socket通信平滑交接,因此只能完整重启
|
||||
if runtime.GOOS != "windows" {
|
||||
fd = gconv.Int(array[1])
|
||||
}
|
||||
}
|
||||
if fd > 0 {
|
||||
s.servers = append(s.servers, s.newGracefulServer(addr, fd))
|
||||
s.servers = append(s.servers, s.newGracefulServer(itemFunc, fd))
|
||||
} else {
|
||||
s.servers = append(s.servers, s.newGracefulServer(addr))
|
||||
s.servers = append(s.servers, s.newGracefulServer(itemFunc))
|
||||
}
|
||||
}
|
||||
// 开始执行异步监听
|
||||
@ -523,7 +509,7 @@ func (s *Server) getListenerFdMap() map[string]string {
|
||||
}
|
||||
// s.servers是从HTTPS到HTTP优先级遍历,解析的时候也应当按照这个顺序读取fd
|
||||
for _, v := range s.servers {
|
||||
str := v.addr + "#" + gconv.String(v.Fd()) + ","
|
||||
str := v.itemFunc + "#" + gconv.String(v.Fd()) + ","
|
||||
if v.isHttps {
|
||||
m["https"] += str
|
||||
} else {
|
||||
|
||||
@ -91,33 +91,28 @@ type ServerConfig struct {
|
||||
|
||||
// 默认HTTP Server配置
|
||||
var defaultServerConfig = ServerConfig{
|
||||
Addr: "",
|
||||
HTTPSAddr: "",
|
||||
Handler: nil,
|
||||
ReadTimeout: 60 * time.Second,
|
||||
WriteTimeout: 60 * time.Second,
|
||||
IdleTimeout: 60 * time.Second,
|
||||
MaxHeaderBytes: 1024,
|
||||
KeepAlive: true,
|
||||
|
||||
Addr: "",
|
||||
HTTPSAddr: "",
|
||||
Handler: nil,
|
||||
ReadTimeout: 60 * time.Second,
|
||||
WriteTimeout: 60 * time.Second,
|
||||
IdleTimeout: 60 * time.Second,
|
||||
MaxHeaderBytes: 1024,
|
||||
KeepAlive: true,
|
||||
IndexFiles: []string{"index.html", "index.htm"},
|
||||
IndexFolder: false,
|
||||
ServerAgent: "gf",
|
||||
ServerRoot: "",
|
||||
StaticPaths: make([]staticPathItem, 0),
|
||||
FileServerEnabled: false,
|
||||
|
||||
CookieMaxAge: gDEFAULT_COOKIE_MAX_AGE,
|
||||
CookiePath: gDEFAULT_COOKIE_PATH,
|
||||
CookieDomain: "",
|
||||
|
||||
SessionMaxAge: gDEFAULT_SESSION_MAX_AGE,
|
||||
SessionIdName: gDEFAULT_SESSION_ID_NAME,
|
||||
|
||||
CookieMaxAge: gDEFAULT_COOKIE_MAX_AGE,
|
||||
CookiePath: gDEFAULT_COOKIE_PATH,
|
||||
CookieDomain: "",
|
||||
SessionMaxAge: gDEFAULT_SESSION_MAX_AGE,
|
||||
SessionIdName: gDEFAULT_SESSION_ID_NAME,
|
||||
LogStdout: true,
|
||||
ErrorLogEnabled: true,
|
||||
AccessLogEnabled: false,
|
||||
GzipContentTypes: defaultGzipContentTypes,
|
||||
DumpRouteMap: true,
|
||||
RouterCacheExpire: 60,
|
||||
Rewrites: make(map[string]string),
|
||||
@ -146,12 +141,12 @@ func (s *Server) SetConfig(c ServerConfig) {
|
||||
}
|
||||
|
||||
// 设置http server参数 - Addr
|
||||
func (s *Server) SetAddr(addr string) {
|
||||
func (s *Server) SetAddr(itemFunc string) {
|
||||
if s.Status() == SERVER_STATUS_RUNNING {
|
||||
glog.Error(gCHANGE_CONFIG_WHILE_RUNNING_ERROR)
|
||||
return
|
||||
}
|
||||
s.config.Addr = addr
|
||||
s.config.Addr = itemFunc
|
||||
}
|
||||
|
||||
// 设置http server参数 - Port
|
||||
@ -171,12 +166,12 @@ func (s *Server) SetPort(port ...int) {
|
||||
}
|
||||
|
||||
// 设置http server参数 - HTTPS Addr
|
||||
func (s *Server) SetHTTPSAddr(addr string) {
|
||||
func (s *Server) SetHTTPSAddr(itemFunc string) {
|
||||
if s.Status() == SERVER_STATUS_RUNNING {
|
||||
glog.Error(gCHANGE_CONFIG_WHILE_RUNNING_ERROR)
|
||||
return
|
||||
}
|
||||
s.config.HTTPSAddr = addr
|
||||
s.config.HTTPSAddr = itemFunc
|
||||
}
|
||||
|
||||
// 设置http server参数 - HTTPS Port
|
||||
|
||||
@ -23,7 +23,7 @@ import (
|
||||
// 优雅的Web Server对象封装
|
||||
type gracefulServer struct {
|
||||
fd uintptr // 热重启时传递的socket监听文件句柄
|
||||
addr string // 监听地址信息
|
||||
itemFunc string // 监听地址信息
|
||||
httpServer *http.Server // 底层http.Server
|
||||
rawListener net.Listener // 原始listener
|
||||
listener net.Listener // 接口化封装的listener
|
||||
@ -32,10 +32,10 @@ type gracefulServer struct {
|
||||
}
|
||||
|
||||
// 创建一个优雅的Http Server
|
||||
func (s *Server) newGracefulServer(addr string, fd ...int) *gracefulServer {
|
||||
func (s *Server) newGracefulServer(itemFunc string, fd ...int) *gracefulServer {
|
||||
gs := &gracefulServer{
|
||||
addr: addr,
|
||||
httpServer: s.newHttpServer(addr),
|
||||
itemFunc: itemFunc,
|
||||
httpServer: s.newHttpServer(itemFunc),
|
||||
}
|
||||
// 是否有继承的文件描述符
|
||||
if len(fd) > 0 && fd[0] > 0 {
|
||||
@ -45,9 +45,9 @@ func (s *Server) newGracefulServer(addr string, fd ...int) *gracefulServer {
|
||||
}
|
||||
|
||||
// 生成一个底层的Web Server对象
|
||||
func (s *Server) newHttpServer(addr string) *http.Server {
|
||||
func (s *Server) newHttpServer(itemFunc string) *http.Server {
|
||||
server := &http.Server{
|
||||
Addr: addr,
|
||||
Addr: itemFunc,
|
||||
Handler: s.config.Handler,
|
||||
ReadTimeout: s.config.ReadTimeout,
|
||||
WriteTimeout: s.config.WriteTimeout,
|
||||
@ -60,8 +60,8 @@ func (s *Server) newHttpServer(addr string) *http.Server {
|
||||
|
||||
// 执行HTTP监听
|
||||
func (s *gracefulServer) ListenAndServe() error {
|
||||
addr := s.httpServer.Addr
|
||||
ln, err := s.getNetListener(addr)
|
||||
itemFunc := s.httpServer.Addr
|
||||
ln, err := s.getNetListener(itemFunc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -88,7 +88,7 @@ func (s *gracefulServer) setFd(fd int) {
|
||||
|
||||
// 执行HTTPS监听
|
||||
func (s *gracefulServer) ListenAndServeTLS(certFile, keyFile string, tlsConfig ...*tls.Config) error {
|
||||
addr := s.httpServer.Addr
|
||||
itemFunc := s.httpServer.Addr
|
||||
config := (*tls.Config)(nil)
|
||||
if len(tlsConfig) > 0 {
|
||||
config = tlsConfig[0]
|
||||
@ -106,7 +106,7 @@ func (s *gracefulServer) ListenAndServeTLS(certFile, keyFile string, tlsConfig .
|
||||
if err != nil {
|
||||
return errors.New(fmt.Sprintf(`open cert file "%s","%s" failed: %s`, certFile, keyFile, err.Error()))
|
||||
}
|
||||
ln, err := s.getNetListener(addr)
|
||||
ln, err := s.getNetListener(itemFunc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -131,7 +131,7 @@ func (s *gracefulServer) doServe() error {
|
||||
if s.fd != 0 {
|
||||
action = "reloaded"
|
||||
}
|
||||
glog.Printf("%d: %s server %s listening on [%s]", gproc.Pid(), s.getProto(), action, s.addr)
|
||||
glog.Printf("%d: %s server %s listening on [%s]", gproc.Pid(), s.getProto(), action, s.itemFunc)
|
||||
s.status = SERVER_STATUS_RUNNING
|
||||
err := s.httpServer.Serve(s.listener)
|
||||
s.status = SERVER_STATUS_STOPPED
|
||||
@ -139,7 +139,7 @@ func (s *gracefulServer) doServe() error {
|
||||
}
|
||||
|
||||
// 自定义的net.Listener
|
||||
func (s *gracefulServer) getNetListener(addr string) (net.Listener, error) {
|
||||
func (s *gracefulServer) getNetListener(itemFunc string) (net.Listener, error) {
|
||||
var ln net.Listener
|
||||
var err error
|
||||
if s.fd > 0 {
|
||||
@ -152,7 +152,7 @@ func (s *gracefulServer) getNetListener(addr string) (net.Listener, error) {
|
||||
} else {
|
||||
// 如果监听失败,1秒后重试,最多重试3次
|
||||
for i := 0; i < 3; i++ {
|
||||
ln, err = net.Listen("tcp", addr)
|
||||
ln, err = net.Listen("tcp", itemFunc)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("%d: net.Listen error: %v", gproc.Pid(), err)
|
||||
time.Sleep(time.Second)
|
||||
@ -174,7 +174,7 @@ func (s *gracefulServer) shutdown() {
|
||||
return
|
||||
}
|
||||
if err := s.httpServer.Shutdown(context.Background()); err != nil {
|
||||
glog.Errorf("%d: %s server [%s] shutdown error: %v", gproc.Pid(), s.getProto(), s.addr, err)
|
||||
glog.Errorf("%d: %s server [%s] shutdown error: %v", gproc.Pid(), s.getProto(), s.itemFunc, err)
|
||||
}
|
||||
}
|
||||
|
||||
@ -184,6 +184,6 @@ func (s *gracefulServer) close() {
|
||||
return
|
||||
}
|
||||
if err := s.httpServer.Close(); err != nil {
|
||||
glog.Errorf("%d: %s server [%s] closed error: %v", gproc.Pid(), s.getProto(), s.addr, err)
|
||||
glog.Errorf("%d: %s server [%s] closed error: %v", gproc.Pid(), s.getProto(), s.itemFunc, err)
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,7 +9,6 @@ package ghttp
|
||||
import (
|
||||
"net/http"
|
||||
"os"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
@ -97,19 +96,12 @@ func (s *Server) handleRequest(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
// 动态服务检索
|
||||
handler := (*handlerItem)(nil)
|
||||
if !request.isFileRequest || isStaticDir {
|
||||
if parsedItem := s.getServeHandlerWithCache(request); parsedItem != nil {
|
||||
handler = parsedItem.handler
|
||||
for k, v := range parsedItem.values {
|
||||
request.routerVars[k] = v
|
||||
}
|
||||
request.Router = parsedItem.handler.router
|
||||
}
|
||||
request.handlers = s.getHandlersWithCache(request)
|
||||
}
|
||||
|
||||
// 判断最终对该请求提供的服务方式
|
||||
if isStaticDir && handler != nil {
|
||||
if isStaticDir && request.handlers != nil {
|
||||
request.isFileRequest = false
|
||||
}
|
||||
|
||||
@ -118,14 +110,13 @@ func (s *Server) handleRequest(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// 执行静态文件服务/回调控制器/执行对象/方法
|
||||
if !request.IsExited() {
|
||||
// 需要再次判断文件是否真实存在,
|
||||
// 因为文件检索可能使用了缓存,从健壮性考虑这里需要二次判断
|
||||
if request.isFileRequest /* && gfile.Exists(staticFile) */ {
|
||||
if request.isFileRequest {
|
||||
// 静态服务
|
||||
s.serveFile(request, staticFile)
|
||||
} else {
|
||||
if handler != nil {
|
||||
if request.handlers != nil {
|
||||
// 动态服务
|
||||
s.callServeHandler(handler, request)
|
||||
request.MiddleWare.Next()
|
||||
} else {
|
||||
if isStaticDir {
|
||||
// 静态目录
|
||||
@ -172,59 +163,6 @@ func (s *Server) searchStaticFile(uri string) (filePath string, isDir bool) {
|
||||
return "", false
|
||||
}
|
||||
|
||||
// 调用服务接口
|
||||
func (s *Server) callServeHandler(h *handlerItem, r *Request) {
|
||||
if h.faddr == nil {
|
||||
c := reflect.New(h.ctype)
|
||||
s.niceCallFunc(func() {
|
||||
c.MethodByName("Init").Call([]reflect.Value{reflect.ValueOf(r)})
|
||||
})
|
||||
if !r.IsExited() {
|
||||
s.niceCallFunc(func() {
|
||||
c.MethodByName(h.fname).Call(nil)
|
||||
})
|
||||
}
|
||||
if !r.IsExited() {
|
||||
s.niceCallFunc(func() {
|
||||
c.MethodByName("Shut").Call(nil)
|
||||
})
|
||||
}
|
||||
} else {
|
||||
if h.finit != nil {
|
||||
s.niceCallFunc(func() {
|
||||
h.finit(r)
|
||||
})
|
||||
}
|
||||
if !r.IsExited() {
|
||||
s.niceCallFunc(func() {
|
||||
h.faddr(r)
|
||||
})
|
||||
}
|
||||
if h.fshut != nil && !r.IsExited() {
|
||||
s.niceCallFunc(func() {
|
||||
h.fshut(r)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 友好地调用方法
|
||||
func (s *Server) niceCallFunc(f func()) {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
switch err {
|
||||
case gEXCEPTION_EXIT:
|
||||
fallthrough
|
||||
case gEXCEPTION_EXIT_ALL:
|
||||
return
|
||||
default:
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
f()
|
||||
}
|
||||
|
||||
// http server静态文件处理,path可以为相对路径也可以为绝对路径
|
||||
func (s *Server) serveFile(r *Request, path string, allowIndex ...bool) {
|
||||
f, err := os.Open(path)
|
||||
|
||||
@ -3,7 +3,6 @@
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
// 路由控制基本方法.
|
||||
|
||||
package ghttp
|
||||
|
||||
@ -49,17 +48,18 @@ func (s *Server) parsePattern(pattern string) (domain, method, path string, err
|
||||
// 获得服务注册的文件地址信息
|
||||
func (s *Server) getHandlerRegisterCallerLine(handler *handlerItem) string {
|
||||
skip := 5
|
||||
if handler.rtype == gROUTE_REGISTER_HANDLER {
|
||||
if handler.itemType == gHANDLER_TYPE_HANDLER {
|
||||
skip = 4
|
||||
}
|
||||
if _, cfile, cline, ok := runtime.Caller(skip); ok {
|
||||
return fmt.Sprintf("%s:%d", cfile, cline)
|
||||
if _, file, line, ok := runtime.Caller(skip); ok {
|
||||
return fmt.Sprintf("%s:%d", file, line)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// 路由注册处理方法。
|
||||
// 如果带有hook参数,表示是回调注册方法; 否则为普通路由执行方法。
|
||||
// 非叶节点为哈希表检索节点,按照URI注册的层级进行高效检索,直至到叶子链表节点;
|
||||
// 叶子节点是链表,按照优先级进行排序,优先级高的排前面,按照遍历检索,按照哈希表层级检索后的叶子链表数据量不会很大,所以效率比较高;
|
||||
func (s *Server) setHandler(pattern string, handler *handlerItem, hook ...string) {
|
||||
// Web Server正常运行时无法动态注册路由方法
|
||||
if s.Status() == SERVER_STATUS_RUNNING {
|
||||
@ -89,7 +89,7 @@ func (s *Server) setHandler(pattern string, handler *handlerItem, hook ...string
|
||||
}
|
||||
}
|
||||
|
||||
// 路由对象
|
||||
// 注册的路由信息对象
|
||||
handler.router = &Router{
|
||||
Uri: uri,
|
||||
Domain: domain,
|
||||
@ -98,20 +98,11 @@ func (s *Server) setHandler(pattern string, handler *handlerItem, hook ...string
|
||||
}
|
||||
handler.router.RegRule, handler.router.RegNames = s.patternToRegRule(uri)
|
||||
|
||||
// 动态注册,首先需要判断是否是动态注册,如果不是那么就没必要添加到动态注册记录变量中。
|
||||
// 非叶节点为哈希表检索节点,按照URI注册的层级进行高效检索,直至到叶子链表节点;
|
||||
// 叶子节点是链表,按照优先级进行排序,优先级高的排前面,按照遍历检索,按照哈希表层级检索后的叶子链表数据量不会很大,所以效率比较高;
|
||||
tree := (map[string]interface{})(nil)
|
||||
if len(hookName) == 0 {
|
||||
tree = s.serveTree
|
||||
} else {
|
||||
tree = s.hooksTree
|
||||
}
|
||||
if _, ok := tree[domain]; !ok {
|
||||
tree[domain] = make(map[string]interface{})
|
||||
if _, ok := s.serveTree[domain]; !ok {
|
||||
s.serveTree[domain] = make(map[string]interface{})
|
||||
}
|
||||
// 用于遍历的指针
|
||||
p := tree[domain]
|
||||
p := s.serveTree[domain]
|
||||
if len(hookName) > 0 {
|
||||
if _, ok := p.(map[string]interface{})[hookName]; !ok {
|
||||
p.(map[string]interface{})[hookName] = make(map[string]interface{})
|
||||
@ -166,22 +157,27 @@ func (s *Server) setHandler(pattern string, handler *handlerItem, hook ...string
|
||||
pushed := false
|
||||
for e := l.Front(); e != nil; e = e.Next() {
|
||||
item = e.Value.(*handlerItem)
|
||||
// 判断是否已存在相同的路由注册项,(如果不是hook注册)是则进行替换
|
||||
if len(hookName) == 0 {
|
||||
if strings.EqualFold(handler.router.Domain, item.router.Domain) &&
|
||||
strings.EqualFold(handler.router.Method, item.router.Method) &&
|
||||
strings.EqualFold(handler.router.Uri, item.router.Uri) {
|
||||
e.Value = handler
|
||||
switch handler.itemType {
|
||||
// 判断是否已存在相同的路由注册项,如果是普通路由注册则进行替换
|
||||
case gHANDLER_TYPE_HANDLER, gHANDLER_TYPE_OBJECT, gHANDLER_TYPE_CONTROLLER:
|
||||
if handler.itemType == gHANDLER_TYPE_HANDLER {
|
||||
if strings.EqualFold(handler.router.Domain, item.router.Domain) &&
|
||||
strings.EqualFold(handler.router.Method, item.router.Method) &&
|
||||
strings.EqualFold(handler.router.Uri, item.router.Uri) {
|
||||
e.Value = handler
|
||||
pushed = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// 否则,那么判断优先级,决定插入顺序
|
||||
default:
|
||||
if s.compareRouterPriority(handler.router, item.router) {
|
||||
l.InsertBefore(handler, e)
|
||||
pushed = true
|
||||
break
|
||||
}
|
||||
}
|
||||
// 如果路由注册项不相等,那么判断优先级,决定插入顺序
|
||||
if s.compareRouterPriority(handler.router, item.router) {
|
||||
l.InsertBefore(handler, e)
|
||||
pushed = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !pushed {
|
||||
l.PushBack(handler)
|
||||
|
||||
@ -3,7 +3,6 @@
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
// 分组路由管理.
|
||||
|
||||
package ghttp
|
||||
|
||||
|
||||
@ -3,28 +3,24 @@
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
// 事件回调(中间件)路由控制.
|
||||
|
||||
package ghttp
|
||||
|
||||
import (
|
||||
"container/list"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/gogf/gf/container/gset"
|
||||
"github.com/gogf/gf/text/gregex"
|
||||
)
|
||||
|
||||
// 绑定指定的hook回调函数, pattern参数同BindHandler,支持命名路由;hook参数的值由ghttp server设定,参数不区分大小写
|
||||
func (s *Server) BindHookHandler(pattern string, hook string, handler HandlerFunc) {
|
||||
s.setHandler(pattern, &handlerItem{
|
||||
name: runtime.FuncForPC(reflect.ValueOf(handler).Pointer()).Name(),
|
||||
ctype: nil,
|
||||
fname: "",
|
||||
faddr: handler,
|
||||
itemType: gHANDLER_TYPE_HOOK,
|
||||
itemName: runtime.FuncForPC(reflect.ValueOf(handler).Pointer()).Name(),
|
||||
itemFunc: handler,
|
||||
}, hook)
|
||||
}
|
||||
|
||||
@ -63,7 +59,7 @@ func (s *Server) callHookHandler(hook string, r *Request) {
|
||||
}
|
||||
// 不使用hook的router对象,保留路由注册服务的router对象,不能覆盖
|
||||
// r.Router = item.handler.router
|
||||
if err := s.niceCallHookHandler(item.handler.faddr, r); err != nil {
|
||||
if err := s.niceCallHookHandler(item.handler.itemFunc, r); err != nil {
|
||||
switch err {
|
||||
case gEXCEPTION_EXIT:
|
||||
break
|
||||
@ -122,7 +118,7 @@ func (s *Server) searchHookHandler(method, path, domain, hook string) []*handler
|
||||
} else {
|
||||
array = strings.Split(path[1:], "/")
|
||||
}
|
||||
parsedItems := make([]*handlerParsedItem, 0)
|
||||
parsedItems := make([]*handlerParsedItem, 0, 8)
|
||||
for _, domain := range domains {
|
||||
p, ok := s.hooksTree[domain]
|
||||
if !ok {
|
||||
@ -163,7 +159,6 @@ func (s *Server) searchHookHandler(method, path, domain, hook string) []*handler
|
||||
}
|
||||
|
||||
// 多层链表遍历检索,从数组末尾的链表开始遍历,末尾的深度高优先级也高
|
||||
pushedSet := gset.NewStringSet()
|
||||
for i := len(lists) - 1; i >= 0; i-- {
|
||||
for e := lists[i].Front(); e != nil; e = e.Next() {
|
||||
handler := e.Value.(*handlerItem)
|
||||
@ -186,11 +181,7 @@ func (s *Server) searchHookHandler(method, path, domain, hook string) []*handler
|
||||
}
|
||||
}
|
||||
}
|
||||
address := fmt.Sprintf("%p", handler)
|
||||
if !pushedSet.Contains(address) {
|
||||
parsedItems = append(parsedItems, parsedItem)
|
||||
pushedSet.Add(address)
|
||||
}
|
||||
parsedItems = append(parsedItems, parsedItem)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
7
net/ghttp/ghttp_server_router_middleware.go
Normal file
7
net/ghttp/ghttp_server_router_middleware.go
Normal file
@ -0,0 +1,7 @@
|
||||
// Copyright 2018 gf Author(https://github.com/gogf/gf). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package ghttp
|
||||
@ -3,7 +3,6 @@
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
// 服务注册路由控制.
|
||||
|
||||
package ghttp
|
||||
|
||||
@ -16,26 +15,29 @@ import (
|
||||
|
||||
// 查询请求处理方法.
|
||||
// 内部带锁机制,可以并发读,但是不能并发写;并且有缓存机制,按照Host、Method、Path进行缓存.
|
||||
func (s *Server) getServeHandlerWithCache(r *Request) *handlerParsedItem {
|
||||
cacheItem := (*handlerParsedItem)(nil)
|
||||
func (s *Server) getHandlersWithCache(r *Request) []*handlerParsedItem {
|
||||
cacheKey := s.serveHandlerKey(r.Method, r.URL.Path, r.GetHost())
|
||||
cacheItems := ([]*handlerParsedItem)(nil)
|
||||
if v := s.serveCache.Get(cacheKey); v == nil {
|
||||
cacheItem = s.searchServeHandler(r.Method, r.URL.Path, r.GetHost())
|
||||
if cacheItem != nil {
|
||||
s.serveCache.Set(cacheKey, cacheItem, s.config.RouterCacheExpire*1000)
|
||||
cacheItems = s.searchHandlers(r.Method, r.URL.Path, r.GetHost())
|
||||
if cacheItems != nil {
|
||||
s.serveCache.Set(cacheKey, cacheItems, s.config.RouterCacheExpire*1000)
|
||||
}
|
||||
} else {
|
||||
cacheItem = v.(*handlerParsedItem)
|
||||
cacheItems = v.([]*handlerParsedItem)
|
||||
}
|
||||
return cacheItem
|
||||
if len(cacheItems) == 0 {
|
||||
return nil
|
||||
}
|
||||
return cacheItems
|
||||
}
|
||||
|
||||
// 服务方法检索
|
||||
func (s *Server) searchServeHandler(method, path, domain string) *handlerParsedItem {
|
||||
// 路由注册方法检索,返回所有该路由的注册函数,构造成数组返回
|
||||
func (s *Server) searchHandlers(method, path, domain string) []*handlerParsedItem {
|
||||
if len(path) == 0 {
|
||||
return nil
|
||||
}
|
||||
// 遍历检索的域名列表
|
||||
// 遍历检索的域名列表,优先遍历默认域名
|
||||
domains := []string{gDEFAULT_DOMAIN}
|
||||
if !strings.EqualFold(gDEFAULT_DOMAIN, domain) {
|
||||
domains = append(domains, domain)
|
||||
@ -47,13 +49,15 @@ func (s *Server) searchServeHandler(method, path, domain string) *handlerParsedI
|
||||
} else {
|
||||
array = strings.Split(path[1:], "/")
|
||||
}
|
||||
parsedItems := make([]*handlerParsedItem, 0, 16)
|
||||
isServeHandlerAdded := false
|
||||
for _, domain := range domains {
|
||||
p, ok := s.serveTree[domain]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
// 多层链表(每个节点都有一个*list链表)的目的是当叶子节点未有任何规则匹配时,让父级模糊匹配规则继续处理
|
||||
lists := make([]*list.List, 0)
|
||||
lists := make([]*list.List, 0, 16)
|
||||
for k, v := range array {
|
||||
if _, ok := p.(map[string]interface{})["*list"]; ok {
|
||||
lists = append(lists, p.(map[string]interface{})["*list"].(*list.List))
|
||||
@ -86,6 +90,13 @@ func (s *Server) searchServeHandler(method, path, domain string) *handlerParsedI
|
||||
for i := len(lists) - 1; i >= 0; i-- {
|
||||
for e := lists[i].Front(); e != nil; e = e.Next() {
|
||||
item := e.Value.(*handlerItem)
|
||||
// 服务路由函数只能添加一次
|
||||
if isServeHandlerAdded {
|
||||
switch item.itemType {
|
||||
case gHANDLER_TYPE_HANDLER, gHANDLER_TYPE_OBJECT, gHANDLER_TYPE_CONTROLLER:
|
||||
continue
|
||||
}
|
||||
}
|
||||
// 动态匹配规则带有gDEFAULT_METHOD的情况,不会像静态规则那样直接解析为所有的HTTP METHOD存储
|
||||
if strings.EqualFold(item.router.Method, gDEFAULT_METHOD) || strings.EqualFold(item.router.Method, method) {
|
||||
// 注意当不带任何动态路由规则时,len(match) == 1
|
||||
@ -105,13 +116,20 @@ func (s *Server) searchServeHandler(method, path, domain string) *handlerParsedI
|
||||
}
|
||||
}
|
||||
}
|
||||
return parsedItem
|
||||
parsedItems = append(parsedItems, parsedItem)
|
||||
// 服务路由函数只能添加一次
|
||||
if !isServeHandlerAdded {
|
||||
switch item.itemType {
|
||||
case gHANDLER_TYPE_HANDLER, gHANDLER_TYPE_OBJECT, gHANDLER_TYPE_CONTROLLER:
|
||||
isServeHandlerAdded = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
return parsedItems
|
||||
}
|
||||
|
||||
// 生成回调方法查询的Key
|
||||
|
||||
@ -71,11 +71,12 @@ func (s *Server) BindController(pattern string, c Controller, methods ...string)
|
||||
}
|
||||
key := s.mergeBuildInNameToPattern(pattern, sname, mname, true)
|
||||
m[key] = &handlerItem{
|
||||
name: fmt.Sprintf(`%s.%s.%s`, pkgPath, ctlName, mname),
|
||||
rtype: gROUTE_REGISTER_CONTROLLER,
|
||||
ctype: v.Elem().Type(),
|
||||
fname: mname,
|
||||
faddr: nil,
|
||||
itemName: fmt.Sprintf(`%s.%s.%s`, pkgPath, ctlName, mname),
|
||||
itemType: gHANDLER_TYPE_CONTROLLER,
|
||||
ctrlInfo: &handlerController{
|
||||
name: mname,
|
||||
reflect: v.Elem().Type(),
|
||||
},
|
||||
}
|
||||
// 如果方法中带有Index方法,那么额外自动增加一个路由规则匹配主URI,
|
||||
// 例如: pattern为/user, 那么会同时注册/user及/user/index,
|
||||
@ -88,11 +89,12 @@ func (s *Server) BindController(pattern string, c Controller, methods ...string)
|
||||
k = "/" + k
|
||||
}
|
||||
m[k] = &handlerItem{
|
||||
name: fmt.Sprintf(`%s.%s.%s`, pkgPath, ctlName, mname),
|
||||
rtype: gROUTE_REGISTER_CONTROLLER,
|
||||
ctype: v.Elem().Type(),
|
||||
fname: mname,
|
||||
faddr: nil,
|
||||
itemName: fmt.Sprintf(`%s.%s.%s`, pkgPath, ctlName, mname),
|
||||
itemType: gHANDLER_TYPE_CONTROLLER,
|
||||
ctrlInfo: &handlerController{
|
||||
name: mname,
|
||||
reflect: v.Elem().Type(),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -124,11 +126,12 @@ func (s *Server) BindControllerMethod(pattern string, c Controller, method strin
|
||||
}
|
||||
key := s.mergeBuildInNameToPattern(pattern, sname, mname, false)
|
||||
m[key] = &handlerItem{
|
||||
name: fmt.Sprintf(`%s.%s.%s`, pkgPath, ctlName, mname),
|
||||
rtype: gROUTE_REGISTER_CONTROLLER,
|
||||
ctype: v.Elem().Type(),
|
||||
fname: mname,
|
||||
faddr: nil,
|
||||
itemName: fmt.Sprintf(`%s.%s.%s`, pkgPath, ctlName, mname),
|
||||
itemType: gHANDLER_TYPE_CONTROLLER,
|
||||
ctrlInfo: &handlerController{
|
||||
name: mname,
|
||||
reflect: v.Elem().Type(),
|
||||
},
|
||||
}
|
||||
s.bindHandlerByMap(m)
|
||||
}
|
||||
@ -163,11 +166,12 @@ func (s *Server) BindControllerRest(pattern string, c Controller) {
|
||||
}
|
||||
key := s.mergeBuildInNameToPattern(mname+":"+pattern, sname, mname, false)
|
||||
m[key] = &handlerItem{
|
||||
name: fmt.Sprintf(`%s.%s.%s`, pkgPath, ctlName, mname),
|
||||
rtype: gROUTE_REGISTER_CONTROLLER,
|
||||
ctype: v.Elem().Type(),
|
||||
fname: mname,
|
||||
faddr: nil,
|
||||
itemName: fmt.Sprintf(`%s.%s.%s`, pkgPath, ctlName, mname),
|
||||
itemType: gHANDLER_TYPE_CONTROLLER,
|
||||
ctrlInfo: &handlerController{
|
||||
name: mname,
|
||||
reflect: v.Elem().Type(),
|
||||
},
|
||||
}
|
||||
}
|
||||
s.bindHandlerByMap(m)
|
||||
|
||||
@ -19,11 +19,9 @@ import (
|
||||
// 注意该方法是直接绑定函数的内存地址,执行的时候直接执行该方法,不会存在初始化新的控制器逻辑
|
||||
func (s *Server) BindHandler(pattern string, handler HandlerFunc) {
|
||||
s.bindHandlerItem(pattern, &handlerItem{
|
||||
name: runtime.FuncForPC(reflect.ValueOf(handler).Pointer()).Name(),
|
||||
rtype: gROUTE_REGISTER_HANDLER,
|
||||
ctype: nil,
|
||||
fname: "",
|
||||
faddr: handler,
|
||||
itemName: runtime.FuncForPC(reflect.ValueOf(handler).Pointer()).Name(),
|
||||
itemType: gHANDLER_TYPE_HANDLER,
|
||||
itemFunc: handler,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@ -41,13 +41,13 @@ func (s *Server) BindObject(pattern string, obj interface{}, methods ...string)
|
||||
v := reflect.ValueOf(obj)
|
||||
t := v.Type()
|
||||
sname := t.Elem().Name()
|
||||
finit := (func(*Request))(nil)
|
||||
fshut := (func(*Request))(nil)
|
||||
initFunc := (func(*Request))(nil)
|
||||
shutFunc := (func(*Request))(nil)
|
||||
if v.MethodByName("Init").IsValid() {
|
||||
finit = v.MethodByName("Init").Interface().(func(*Request))
|
||||
initFunc = v.MethodByName("Init").Interface().(func(*Request))
|
||||
}
|
||||
if v.MethodByName("Shut").IsValid() {
|
||||
fshut = v.MethodByName("Shut").Interface().(func(*Request))
|
||||
shutFunc = v.MethodByName("Shut").Interface().(func(*Request))
|
||||
}
|
||||
pkgPath := t.Elem().PkgPath()
|
||||
pkgName := gfile.Basename(pkgPath)
|
||||
@ -63,7 +63,7 @@ func (s *Server) BindObject(pattern string, obj interface{}, methods ...string)
|
||||
if objName[0] == '*' {
|
||||
objName = fmt.Sprintf(`(%s)`, objName)
|
||||
}
|
||||
faddr, ok := v.Method(i).Interface().(func(*Request))
|
||||
itemFunc, ok := v.Method(i).Interface().(func(*Request))
|
||||
if !ok {
|
||||
if len(methodMap) > 0 {
|
||||
// 指定的方法名称注册,那么需要使用错误提示
|
||||
@ -78,13 +78,11 @@ func (s *Server) BindObject(pattern string, obj interface{}, methods ...string)
|
||||
}
|
||||
key := s.mergeBuildInNameToPattern(pattern, sname, mname, true)
|
||||
m[key] = &handlerItem{
|
||||
name: fmt.Sprintf(`%s.%s.%s`, pkgPath, objName, mname),
|
||||
rtype: gROUTE_REGISTER_OBJECT,
|
||||
ctype: nil,
|
||||
fname: "",
|
||||
faddr: faddr,
|
||||
finit: finit,
|
||||
fshut: fshut,
|
||||
itemName: fmt.Sprintf(`%s.%s.%s`, pkgPath, objName, mname),
|
||||
itemType: gHANDLER_TYPE_OBJECT,
|
||||
itemFunc: itemFunc,
|
||||
initFunc: initFunc,
|
||||
shutFunc: shutFunc,
|
||||
}
|
||||
// 如果方法中带有Index方法,那么额外自动增加一个路由规则匹配主URI。
|
||||
// 注意,当pattern带有内置变量时,不会自动加该路由。
|
||||
@ -95,13 +93,11 @@ func (s *Server) BindObject(pattern string, obj interface{}, methods ...string)
|
||||
k = "/" + k
|
||||
}
|
||||
m[k] = &handlerItem{
|
||||
name: fmt.Sprintf(`%s.%s.%s`, pkgPath, objName, mname),
|
||||
rtype: gROUTE_REGISTER_OBJECT,
|
||||
ctype: nil,
|
||||
fname: "",
|
||||
faddr: faddr,
|
||||
finit: finit,
|
||||
fshut: fshut,
|
||||
itemName: fmt.Sprintf(`%s.%s.%s`, pkgPath, objName, mname),
|
||||
itemType: gHANDLER_TYPE_OBJECT,
|
||||
itemFunc: itemFunc,
|
||||
initFunc: initFunc,
|
||||
shutFunc: shutFunc,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -121,13 +117,13 @@ func (s *Server) BindObjectMethod(pattern string, obj interface{}, method string
|
||||
glog.Error("invalid method name:" + mname)
|
||||
return
|
||||
}
|
||||
finit := (func(*Request))(nil)
|
||||
fshut := (func(*Request))(nil)
|
||||
initFunc := (func(*Request))(nil)
|
||||
shutFunc := (func(*Request))(nil)
|
||||
if v.MethodByName("Init").IsValid() {
|
||||
finit = v.MethodByName("Init").Interface().(func(*Request))
|
||||
initFunc = v.MethodByName("Init").Interface().(func(*Request))
|
||||
}
|
||||
if v.MethodByName("Shut").IsValid() {
|
||||
fshut = v.MethodByName("Shut").Interface().(func(*Request))
|
||||
shutFunc = v.MethodByName("Shut").Interface().(func(*Request))
|
||||
}
|
||||
pkgPath := t.Elem().PkgPath()
|
||||
pkgName := gfile.Basename(pkgPath)
|
||||
@ -135,7 +131,7 @@ func (s *Server) BindObjectMethod(pattern string, obj interface{}, method string
|
||||
if objName[0] == '*' {
|
||||
objName = fmt.Sprintf(`(%s)`, objName)
|
||||
}
|
||||
faddr, ok := fval.Interface().(func(*Request))
|
||||
itemFunc, ok := fval.Interface().(func(*Request))
|
||||
if !ok {
|
||||
glog.Errorf(`invalid route method: %s.%s.%s defined as "%s", but "func(*ghttp.Request)" is required for object registry`,
|
||||
pkgPath, objName, mname, fval.Type().String())
|
||||
@ -143,13 +139,11 @@ func (s *Server) BindObjectMethod(pattern string, obj interface{}, method string
|
||||
}
|
||||
key := s.mergeBuildInNameToPattern(pattern, sname, mname, false)
|
||||
m[key] = &handlerItem{
|
||||
name: fmt.Sprintf(`%s.%s.%s`, pkgPath, objName, mname),
|
||||
rtype: gROUTE_REGISTER_OBJECT,
|
||||
ctype: nil,
|
||||
fname: "",
|
||||
faddr: faddr,
|
||||
finit: finit,
|
||||
fshut: fshut,
|
||||
itemName: fmt.Sprintf(`%s.%s.%s`, pkgPath, objName, mname),
|
||||
itemType: gHANDLER_TYPE_OBJECT,
|
||||
itemFunc: itemFunc,
|
||||
initFunc: initFunc,
|
||||
shutFunc: shutFunc,
|
||||
}
|
||||
|
||||
s.bindHandlerByMap(m)
|
||||
@ -162,13 +156,13 @@ func (s *Server) BindObjectRest(pattern string, obj interface{}) {
|
||||
v := reflect.ValueOf(obj)
|
||||
t := v.Type()
|
||||
sname := t.Elem().Name()
|
||||
finit := (func(*Request))(nil)
|
||||
fshut := (func(*Request))(nil)
|
||||
initFunc := (func(*Request))(nil)
|
||||
shutFunc := (func(*Request))(nil)
|
||||
if v.MethodByName("Init").IsValid() {
|
||||
finit = v.MethodByName("Init").Interface().(func(*Request))
|
||||
initFunc = v.MethodByName("Init").Interface().(func(*Request))
|
||||
}
|
||||
if v.MethodByName("Shut").IsValid() {
|
||||
fshut = v.MethodByName("Shut").Interface().(func(*Request))
|
||||
shutFunc = v.MethodByName("Shut").Interface().(func(*Request))
|
||||
}
|
||||
pkgPath := t.Elem().PkgPath()
|
||||
for i := 0; i < v.NumMethod(); i++ {
|
||||
@ -182,7 +176,7 @@ func (s *Server) BindObjectRest(pattern string, obj interface{}) {
|
||||
if objName[0] == '*' {
|
||||
objName = fmt.Sprintf(`(%s)`, objName)
|
||||
}
|
||||
faddr, ok := v.Method(i).Interface().(func(*Request))
|
||||
itemFunc, ok := v.Method(i).Interface().(func(*Request))
|
||||
if !ok {
|
||||
glog.Errorf(`invalid route method: %s.%s.%s defined as "%s", but "func(*ghttp.Request)" is required for object registry`,
|
||||
pkgPath, objName, mname, v.Method(i).Type().String())
|
||||
@ -190,13 +184,11 @@ func (s *Server) BindObjectRest(pattern string, obj interface{}) {
|
||||
}
|
||||
key := s.mergeBuildInNameToPattern(mname+":"+pattern, sname, mname, false)
|
||||
m[key] = &handlerItem{
|
||||
name: fmt.Sprintf(`%s.%s.%s`, pkgPath, objName, mname),
|
||||
rtype: gROUTE_REGISTER_OBJECT,
|
||||
ctype: nil,
|
||||
fname: "",
|
||||
faddr: faddr,
|
||||
finit: finit,
|
||||
fshut: fshut,
|
||||
itemName: fmt.Sprintf(`%s.%s.%s`, pkgPath, objName, mname),
|
||||
itemType: gHANDLER_TYPE_OBJECT,
|
||||
itemFunc: itemFunc,
|
||||
initFunc: initFunc,
|
||||
shutFunc: shutFunc,
|
||||
}
|
||||
}
|
||||
s.bindHandlerByMap(m)
|
||||
|
||||
@ -14,8 +14,6 @@ import (
|
||||
// 查询状态码回调函数
|
||||
func (s *Server) getStatusHandler(status int, r *Request) HandlerFunc {
|
||||
domains := []string{r.GetHost(), gDEFAULT_DOMAIN}
|
||||
s.statusHandlerMu.RLock()
|
||||
defer s.statusHandlerMu.RUnlock()
|
||||
for _, domain := range domains {
|
||||
if f, ok := s.statusHandlerMap[s.statusHandlerKey(status, domain)]; ok {
|
||||
return f
|
||||
@ -27,9 +25,7 @@ func (s *Server) getStatusHandler(status int, r *Request) HandlerFunc {
|
||||
// 不同状态码下的回调方法处理
|
||||
// pattern格式:domain#status
|
||||
func (s *Server) setStatusHandler(pattern string, handler HandlerFunc) {
|
||||
s.statusHandlerMu.Lock()
|
||||
s.statusHandlerMap[pattern] = handler
|
||||
s.statusHandlerMu.Unlock()
|
||||
}
|
||||
|
||||
// 生成状态码回调函数map存储键名
|
||||
|
||||
@ -4,7 +4,6 @@
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
// 基本路由功能以及优先级测试
|
||||
package ghttp_test
|
||||
|
||||
import (
|
||||
@ -24,18 +23,18 @@ func Test_Router_Basic(t *testing.T) {
|
||||
s.BindHandler("/:name", func(r *ghttp.Request) {
|
||||
r.Response.Write("/:name")
|
||||
})
|
||||
s.BindHandler("/:name/update", func(r *ghttp.Request) {
|
||||
r.Response.Write(r.Get("name"))
|
||||
})
|
||||
s.BindHandler("/:name/:action", func(r *ghttp.Request) {
|
||||
r.Response.Write(r.Get("action"))
|
||||
})
|
||||
//s.BindHandler("/:name/update", func(r *ghttp.Request) {
|
||||
// r.Response.Write(r.Get("name"))
|
||||
//})
|
||||
//s.BindHandler("/:name/:action", func(r *ghttp.Request) {
|
||||
// r.Response.Write(r.Get("action"))
|
||||
//})
|
||||
s.BindHandler("/:name/*any", func(r *ghttp.Request) {
|
||||
r.Response.Write(r.Get("any"))
|
||||
})
|
||||
s.BindHandler("/user/list/{field}.html", func(r *ghttp.Request) {
|
||||
r.Response.Write(r.Get("field"))
|
||||
})
|
||||
//s.BindHandler("/user/list/{field}.html", func(r *ghttp.Request) {
|
||||
// r.Response.Write(r.Get("field"))
|
||||
//})
|
||||
s.SetPort(p)
|
||||
s.SetDumpRouteMap(false)
|
||||
s.Start()
|
||||
|
||||
Reference in New Issue
Block a user