ghttp.Server增加自定义状态码回调函数注册处理

This commit is contained in:
John
2018-05-04 14:35:20 +08:00
parent c4c6f2ece6
commit fa897c25bc
11 changed files with 122 additions and 12 deletions

6
TODO
View File

@ -6,6 +6,12 @@ ON THE WAY:
5. FAQ
6. gdb对象管理增加二级连接池特性
7. 完善gconv类型转换功能增加time.Time/time.Duration类型转换并增加benchmark测试脚本
8. 增加ghttp.Server不同状态码的自定义处理方法
DONE:
1. gconv完善针对不同类型的判断例如尽量减少sprintf("%v", xxx)来执行string类型的转换

View File

@ -134,15 +134,17 @@ func (r *Response) SetAllowCrossDomainRequest(allowOrigin string, allowMethods s
}
// 返回HTTP Code状态码
func (r *Response) WriteStatus(code int, content...string) {
r.Header().Set("Content-Type", "text/plain; charset=utf-8")
r.Header().Set("X-Content-Type-Options", "nosniff")
if len(content) > 0 {
r.Write(content[0])
} else {
r.Write(http.StatusText(code))
func (r *Response) WriteStatus(status int, content...string) {
if len(r.buffer) == 0 {
r.Header().Set("Content-Type", "text/plain; charset=utf-8")
r.Header().Set("X-Content-Type-Options", "nosniff")
if len(content) > 0 {
r.Write(content[0])
} else {
r.Write(http.StatusText(status))
}
}
r.WriteHeader(code)
r.WriteHeader(status)
}
// 返回location标识引导客户端跳转
@ -158,6 +160,13 @@ func (r *Response) Buffer() []byte {
return r.buffer
}
// 获取当前缓冲区中的数据大小
func (r *Response) BufferLength() int {
r.mu.RLock()
defer r.mu.RUnlock()
return len(r.buffer)
}
// 手动设置缓冲区内容
func (r *Response) SetBuffer(buffer []byte) {
r.mu.Lock()

View File

@ -35,6 +35,7 @@ const (
type Server struct {
hmmu sync.RWMutex // handler互斥锁
hhmu sync.RWMutex // hooks互斥锁
hsmu sync.RWMutex // status handler互斥锁
hmcmu sync.RWMutex // handlerCache互斥锁
hhcmu sync.RWMutex // hooksCache互斥锁
name string // 服务名称,方便识别
@ -42,6 +43,7 @@ type Server struct {
status int8 // 当前服务器状态(0未启动1运行中)
methodsMap map[string]bool // 所有支持的HTTP Method(初始化时自动填充)
handlerMap HandlerMap // 所有注册的回调函数(静态匹配)
statusHandlerMap map[string]HandlerFunc // 不同状态码下的注册处理方法(例如404状态时的处理方法)
handlerTree map[string]interface{} // 所有注册的回调函数(动态匹配,树型+链表优先级匹配)
hooksTree map[string]interface{} // 所有注册的事件回调函数(动态匹配,树型+链表优先级匹配)
handlerCache *gcache.Cache // 服务注册路由内存缓存
@ -100,6 +102,7 @@ func GetServer(name...interface{}) (*Server) {
name : sname,
methodsMap : make(map[string]bool),
handlerMap : make(HandlerMap),
statusHandlerMap : make(map[string]HandlerFunc),
handlerTree : make(map[string]interface{}),
hooksTree : make(map[string]interface{}),
handlerCache : gcache.New(),

View File

@ -132,3 +132,17 @@ func (d *Domain)BindHookHandlerByMap(pattern string, hookmap map[string]HandlerF
}
return nil
}
// 绑定指定的状态码回调函数
func (d *Domain)BindStatusHandler(status int, handler HandlerFunc) {
for domain, _ := range d.m {
d.s.setStatusHandler(d.s.statusHandlerKey(status, domain), handler)
}
}
// 通过map批量绑定状态码回调函数
func (d *Domain)BindStatusHandlerByMap(handlerMap map[int]HandlerFunc) {
for k, v := range handlerMap {
d.BindStatusHandler(k, v)
}
}

View File

@ -58,8 +58,15 @@ func (s *Server)handleRequest(w http.ResponseWriter, r *http.Request) {
}
// 事件 - AfterServe
s.callHookHandler(request, "AfterServe")
// 状态码注册回调函数处理
if f := request.Server.getStatusHandler(request.Response.Status, request); f != nil {
f(request)
}
// 设置请求完成时间
request.LeaveTime = gtime.Microsecond()
// 事件 - BeforeOutput
s.callHookHandler(request, "BeforeOutput")
// 输出Cookie

View File

@ -124,7 +124,7 @@ func (s *Server) searchHookHandler(r *Request, hook string) []*hookCacheItem {
s.hhmu.RLock()
defer s.hhmu.RUnlock()
hookItems := make([]*hookCacheItem, 0)
domains := []string{gDEFAULT_DOMAIN, r.GetHost()}
domains := []string{r.GetHost(), gDEFAULT_DOMAIN}
array := strings.Split(r.URL.Path[1:], "/")
for _, domain := range domains {
p, ok := s.hooksTree[domain]

View File

@ -177,7 +177,7 @@ func (s *Server) searchHandler(r *Request) *handlerCacheItem {
func (s *Server) searchHandlerStatic(r *Request) *handlerCacheItem {
s.hmmu.RLock()
defer s.hmmu.RUnlock()
domains := []string{gDEFAULT_DOMAIN, r.GetHost()}
domains := []string{r.GetHost(), gDEFAULT_DOMAIN}
// 首先进行静态匹配
for _, domain := range domains {
if f, ok := s.handlerMap[s.handlerKey(domain, r.Method, r.URL.Path)]; ok {

View File

@ -3,7 +3,7 @@
// 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://gitee.com/johng/gf.
// 服务注册 + hook管理.
// 服务注册.
package ghttp

View File

@ -0,0 +1,50 @@
// Copyright 2018 gf Author(https://gitee.com/johng/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://gitee.com/johng/gf.
// 状态码回调函数注册.
package ghttp
import (
"fmt"
)
// 查询状态码回调函数
func (s *Server)getStatusHandler(status int, r *Request) HandlerFunc {
domains := []string{r.GetHost(), gDEFAULT_DOMAIN}
s.hsmu.RLock()
defer s.hsmu.RUnlock()
for _, domain := range domains {
if f, ok := s.statusHandlerMap[s.statusHandlerKey(status, domain)]; ok {
return f
}
}
return nil
}
// 不同状态码下的回调方法处理
// pattern格式domain#status
func (s *Server)setStatusHandler(pattern string, handler HandlerFunc) {
s.hsmu.Lock()
s.statusHandlerMap[pattern] = handler
s.hsmu.Unlock()
}
// 生成状态码回调函数map存储键名
func (s *Server)statusHandlerKey(status int, domain string) string {
return fmt.Sprintf("%s#%d", domain, status)
}
// 绑定指定的状态码回调函数
func (s *Server)BindStatusHandler(status int, handler HandlerFunc) {
s.setStatusHandler(s.statusHandlerKey(status, gDEFAULT_DOMAIN), handler)
}
// 通过map批量绑定状态码回调函数
func (s *Server)BindStatusHandlerByMap(handlerMap map[int]HandlerFunc) {
for k, v := range handlerMap {
s.BindStatusHandler(k, v)
}
}

20
geg/net/ghttp/status.go Normal file
View File

@ -0,0 +1,20 @@
package main
import (
"gitee.com/johng/gf/g"
"gitee.com/johng/gf/g/net/ghttp"
)
func main() {
s := g.Server()
s.BindHandler("/", func(r *ghttp.Request){
r.Response.Writeln("halo 世界!")
r.Response.WriteStatus(404)
})
s.BindStatusHandler(404, func(r *ghttp.Request){
r.Response.ClearBuffer()
r.Response.Writeln("This is customized 404 page")
})
s.SetPort(8199)
s.Run()
}

View File

@ -2,8 +2,9 @@ package main
import (
"fmt"
"gitee.com/johng/gf/g/os/gfile"
)
func main() {
fmt.Println(int(float64(149860800000)))
fmt.Println(gfile.RealPath("./"))
}