mirror of
https://gitee.com/johng/gf
synced 2026-06-07 02:12:11 +08:00
ghttp.Server增加自定义状态码回调函数注册处理
This commit is contained in:
6
TODO
6
TODO
@ -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类型的转换;
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -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(),
|
||||
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
|
||||
@ -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]
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
50
g/net/ghttp/http_server_status.go
Normal file
50
g/net/ghttp/http_server_status.go
Normal 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
20
geg/net/ghttp/status.go
Normal 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()
|
||||
}
|
||||
@ -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("./"))
|
||||
}
|
||||
Reference in New Issue
Block a user