mirror of
https://gitee.com/johng/gf
synced 2026-07-04 21:03:13 +08:00
comment updates for package ghttp
This commit is contained in:
@ -35,6 +35,10 @@ var (
|
||||
//
|
||||
// The parameter <pointer> can be type of: *struct/**struct/*[]struct/*[]*struct.
|
||||
//
|
||||
// It supports single and multiple struct convertion:
|
||||
// 1. Single struct, post content like: {"id":1, "name":"john"}
|
||||
// 2. Multiple struct, post content like: [{"id":1, "name":"john"}, {"id":, "name":"smith"}]
|
||||
//
|
||||
// TODO: Improve the performance by reducing duplicated reflect usage on the same variable across packages.
|
||||
func (r *Request) Parse(pointer interface{}) error {
|
||||
var (
|
||||
@ -52,15 +56,20 @@ func (r *Request) Parse(pointer interface{}) error {
|
||||
reflectKind2 = reflectVal2.Kind()
|
||||
)
|
||||
switch reflectKind2 {
|
||||
// Single struct, post content like:
|
||||
// {"id":1, "name":"john"}
|
||||
case reflect.Ptr, reflect.Struct:
|
||||
// Struct conversion.
|
||||
// Conversion.
|
||||
if err := r.GetStruct(pointer); err != nil {
|
||||
return err
|
||||
}
|
||||
// Struct validation.
|
||||
// Validation.
|
||||
if err := gvalid.CheckStruct(pointer, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Multiple struct, post content like:
|
||||
// [{"id":1, "name":"john"}, {"id":, "name":"smith"}]
|
||||
case reflect.Array, reflect.Slice:
|
||||
// If struct slice conversion, it might post JSON/XML content,
|
||||
// so it uses gjson for the conversion.
|
||||
|
||||
@ -13,27 +13,29 @@ import (
|
||||
"github.com/gogf/gf/os/gtime"
|
||||
)
|
||||
|
||||
// COOKIE对象,非并发安全。
|
||||
// Cookie for HTTP COOKIE management.
|
||||
type Cookie struct {
|
||||
data map[string]CookieItem // 数据项
|
||||
path string // 默认的cookie path
|
||||
domain string // 默认的cookie domain
|
||||
maxage time.Duration // 默认的cookie maxage
|
||||
server *Server // 所属Server
|
||||
request *Request // 所属HTTP请求对象
|
||||
response *Response // 所属HTTP返回对象
|
||||
data map[string]CookieItem // Underlying cookie items.
|
||||
path string // The default cookie path.
|
||||
domain string // The default cookie domain
|
||||
maxage time.Duration // The default cookie maxage.
|
||||
server *Server // Belonged HTTP server
|
||||
request *Request // Belonged HTTP request.
|
||||
response *Response // Belonged HTTP response.
|
||||
}
|
||||
|
||||
// cookie项
|
||||
// CookieItem is cookie item stored in Cookie management object.
|
||||
type CookieItem struct {
|
||||
value string
|
||||
domain string // 有效域名
|
||||
path string // 有效路径
|
||||
expireAt int64 // 过期时间
|
||||
value string // Cookie value.
|
||||
domain string // Cookie domain.
|
||||
path string // Cookie path.
|
||||
expireAt int64 // Cookie expiration timestamp.
|
||||
httpOnly bool
|
||||
}
|
||||
|
||||
// 获取或者创建一个COOKIE对象,与传入的请求对应(延迟初始化)
|
||||
// GetCookie creates or retrieves a cookie object with given request.
|
||||
// It retrieves and returns an existing cookie object if it already exists with given request.
|
||||
// It creates and returns a new cookie object if it does not exist with given request.
|
||||
func GetCookie(r *Request) *Cookie {
|
||||
if r.Cookie != nil {
|
||||
return r.Cookie
|
||||
@ -44,7 +46,7 @@ func GetCookie(r *Request) *Cookie {
|
||||
}
|
||||
}
|
||||
|
||||
// 从请求流中初始化,无锁,延迟初始化
|
||||
// init does lazy initialization for cookie object.
|
||||
func (c *Cookie) init() {
|
||||
if c.data == nil {
|
||||
c.data = make(map[string]CookieItem)
|
||||
@ -64,7 +66,7 @@ func (c *Cookie) init() {
|
||||
}
|
||||
}
|
||||
|
||||
// 获取所有的Cookie并构造成map[string]string返回.
|
||||
// Map returns the cookie items as map[string]string.
|
||||
func (c *Cookie) Map() map[string]string {
|
||||
c.init()
|
||||
m := make(map[string]string)
|
||||
@ -74,7 +76,7 @@ func (c *Cookie) Map() map[string]string {
|
||||
return m
|
||||
}
|
||||
|
||||
// 判断Cookie中是否存在制定键名(并且没有过期)
|
||||
// Contains checks if given key exists and not expired in cookie.
|
||||
func (c *Cookie) Contains(key string) bool {
|
||||
c.init()
|
||||
if r, ok := c.data[key]; ok {
|
||||
@ -85,12 +87,14 @@ func (c *Cookie) Contains(key string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// 设置cookie,使用默认参数
|
||||
// Set sets cookie item with default domain, path and expiration age.
|
||||
func (c *Cookie) Set(key, value string) {
|
||||
c.SetCookie(key, value, c.domain, c.path, c.server.GetCookieMaxAge())
|
||||
}
|
||||
|
||||
// 设置cookie,带详细cookie参数
|
||||
// SetCookie sets cookie item given given domain, path and expiration age.
|
||||
// The optional parameter <httpOnly> specifies if the cookie item is only available in HTTP,
|
||||
// which is usually empty.
|
||||
func (c *Cookie) SetCookie(key, value, domain, path string, maxAge time.Duration, httpOnly ...bool) {
|
||||
c.init()
|
||||
isHttpOnly := false
|
||||
@ -102,17 +106,18 @@ func (c *Cookie) SetCookie(key, value, domain, path string, maxAge time.Duration
|
||||
}
|
||||
}
|
||||
|
||||
// 获得客户端提交的SessionId
|
||||
// GetSessionId retrieves and returns the session id from cookie.
|
||||
func (c *Cookie) GetSessionId() string {
|
||||
return c.Get(c.server.GetSessionIdName())
|
||||
}
|
||||
|
||||
// 设置SessionId到Cookie中
|
||||
// SetSessionId sets session id in the cookie.
|
||||
func (c *Cookie) SetSessionId(id string) {
|
||||
c.Set(c.server.GetSessionIdName(), id)
|
||||
}
|
||||
|
||||
// 查询cookie
|
||||
// Get retrieves and returns the value with specified key.
|
||||
// It returns <def> if specified key does not exist and <def> is given.
|
||||
func (c *Cookie) Get(key string, def ...string) string {
|
||||
c.init()
|
||||
if r, ok := c.data[key]; ok {
|
||||
@ -126,24 +131,26 @@ func (c *Cookie) Get(key string, def ...string) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// 删除COOKIE,使用默认的domain&path
|
||||
// Remove deletes specified key and its value from cookie using default domain and path.
|
||||
// It actually tells the http client that the cookie is expired, do not send it to server next time.
|
||||
func (c *Cookie) Remove(key string) {
|
||||
c.SetCookie(key, "", c.domain, c.path, -86400)
|
||||
}
|
||||
|
||||
// 标记该cookie在对应的域名和路径失效
|
||||
// 删除cookie的重点是需要通知浏览器客户端cookie已过期
|
||||
// RemoveCookie deletes specified key and its value from cookie using given domain and path.
|
||||
// It actually tells the http client that the cookie is expired, do not send it to server next time.
|
||||
func (c *Cookie) RemoveCookie(key, domain, path string) {
|
||||
c.SetCookie(key, "", domain, path, -86400)
|
||||
}
|
||||
|
||||
// 输出到客户端
|
||||
// Output outputs the cookie items to client.
|
||||
func (c *Cookie) Output() {
|
||||
if len(c.data) == 0 {
|
||||
return
|
||||
}
|
||||
for k, v := range c.data {
|
||||
// 只有 expire != 0 的才是服务端在本次请求中设置的cookie
|
||||
// Cookie item matches expire != 0 means it is set in this request,
|
||||
// which should be outputted to client.
|
||||
if v.expireAt == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
@ -10,13 +10,13 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// 域名管理器对象
|
||||
// Domain is used for route register for domains.
|
||||
type Domain struct {
|
||||
server *Server // 所属Server
|
||||
domains map[string]struct{} // 多域名
|
||||
server *Server // Belonged server
|
||||
domains map[string]struct{} // Support multiple domains.
|
||||
}
|
||||
|
||||
// 生成一个域名对象, 参数 domains 支持给定多个域名。
|
||||
// Domain creates and returns a domain object for management for one or more domains.
|
||||
func (s *Server) Domain(domains string) *Domain {
|
||||
d := &Domain{
|
||||
server: s,
|
||||
|
||||
@ -19,19 +19,20 @@ import (
|
||||
"os"
|
||||
)
|
||||
|
||||
// 优雅的Web Server对象封装
|
||||
// gracefulServer wraps the net/http.Server with graceful reload/restart feature.
|
||||
type gracefulServer struct {
|
||||
server *Server // Belonged server.
|
||||
fd uintptr // 热重启时传递的socket监听文件句柄
|
||||
address string // 监听地址信息
|
||||
httpServer *http.Server // 底层http.Server
|
||||
rawListener net.Listener // 原始listener
|
||||
listener net.Listener // 接口化封装的listener
|
||||
isHttps bool // 是否HTTPS
|
||||
status int // 当前Server状态(关闭/运行)
|
||||
fd uintptr // File descriptor for passing to child process when graceful reload.
|
||||
address string // Listening address like:":80", ":8080".
|
||||
httpServer *http.Server // Underlying http.Server.
|
||||
rawListener net.Listener // Underlying net.Listener.
|
||||
listener net.Listener // Wrapped net.Listener.
|
||||
isHttps bool // Is HTTPS.
|
||||
status int // Status of current server.
|
||||
}
|
||||
|
||||
// 创建一个优雅的Http Server
|
||||
// newGracefulServer creates and returns a graceful http server with given address.
|
||||
// The optional parameter <fd> specifies the file descriptor which is passed from parent server.
|
||||
func (s *Server) newGracefulServer(address string, fd ...int) *gracefulServer {
|
||||
// Change port to address like: 80 -> :80
|
||||
if gstr.IsNumeric(address) {
|
||||
@ -42,14 +43,13 @@ func (s *Server) newGracefulServer(address string, fd ...int) *gracefulServer {
|
||||
address: address,
|
||||
httpServer: s.newHttpServer(address),
|
||||
}
|
||||
// 是否有继承的文件描述符
|
||||
if len(fd) > 0 && fd[0] > 0 {
|
||||
gs.fd = uintptr(fd[0])
|
||||
}
|
||||
return gs
|
||||
}
|
||||
|
||||
// 生成一个底层的Web Server对象
|
||||
// newGracefulServer creates and returns a underlying http.Server with given address.
|
||||
func (s *Server) newHttpServer(address string) *http.Server {
|
||||
server := &http.Server{
|
||||
Addr: address,
|
||||
@ -64,7 +64,7 @@ func (s *Server) newHttpServer(address string) *http.Server {
|
||||
return server
|
||||
}
|
||||
|
||||
// 执行HTTP监听
|
||||
// ListenAndServe starts listening on configured address.
|
||||
func (s *gracefulServer) ListenAndServe() error {
|
||||
ln, err := s.getNetListener()
|
||||
if err != nil {
|
||||
@ -75,7 +75,8 @@ func (s *gracefulServer) ListenAndServe() error {
|
||||
return s.doServe()
|
||||
}
|
||||
|
||||
// 获得文件描述符
|
||||
// Fd retrieves and returns the file descriptor of current server.
|
||||
// It is available ony in *nix like operation systems like: linux, unix, darwin.
|
||||
func (s *gracefulServer) Fd() uintptr {
|
||||
if s.rawListener != nil {
|
||||
file, err := s.rawListener.(*net.TCPListener).File()
|
||||
@ -86,12 +87,14 @@ func (s *gracefulServer) Fd() uintptr {
|
||||
return 0
|
||||
}
|
||||
|
||||
// 设置自定义fd
|
||||
// setFd sets the file descriptor for current server.
|
||||
func (s *gracefulServer) setFd(fd int) {
|
||||
s.fd = uintptr(fd)
|
||||
}
|
||||
|
||||
// 执行HTTPS监听
|
||||
// ListenAndServeTLS starts listening on configured address with HTTPS.
|
||||
// The parameter <certFile> and <keyFile> specify the necessary certification and key files for HTTPS.
|
||||
// The optional parameter <tlsConfig> specifies the custom TLS configuration.
|
||||
func (s *gracefulServer) ListenAndServeTLS(certFile, keyFile string, tlsConfig ...*tls.Config) error {
|
||||
var config *tls.Config
|
||||
if len(tlsConfig) > 0 && tlsConfig[0] != nil {
|
||||
@ -122,7 +125,7 @@ func (s *gracefulServer) ListenAndServeTLS(certFile, keyFile string, tlsConfig .
|
||||
return s.doServe()
|
||||
}
|
||||
|
||||
// 获取服务协议字符串
|
||||
// getProto retrieves and returns the proto string of current server.
|
||||
func (s *gracefulServer) getProto() string {
|
||||
proto := "http"
|
||||
if s.isHttps {
|
||||
@ -131,7 +134,7 @@ func (s *gracefulServer) getProto() string {
|
||||
return proto
|
||||
}
|
||||
|
||||
// 开始执行Web Server服务处理
|
||||
// doServe does staring the serving.
|
||||
func (s *gracefulServer) doServe() error {
|
||||
action := "started"
|
||||
if s.fd != 0 {
|
||||
@ -147,7 +150,7 @@ func (s *gracefulServer) doServe() error {
|
||||
return err
|
||||
}
|
||||
|
||||
// 自定义的net.Listener
|
||||
// getNetListener retrieves and returns the wrapped net.Listener.
|
||||
func (s *gracefulServer) getNetListener() (net.Listener, error) {
|
||||
var ln net.Listener
|
||||
var err error
|
||||
@ -167,7 +170,7 @@ func (s *gracefulServer) getNetListener() (net.Listener, error) {
|
||||
return ln, err
|
||||
}
|
||||
|
||||
// 执行请求优雅关闭
|
||||
// shutdown shuts down the server gracefully.
|
||||
func (s *gracefulServer) shutdown() {
|
||||
if s.status == SERVER_STATUS_STOPPED {
|
||||
return
|
||||
@ -180,7 +183,7 @@ func (s *gracefulServer) shutdown() {
|
||||
}
|
||||
}
|
||||
|
||||
// 执行请求强制关闭
|
||||
// close shuts down the server forcibly.
|
||||
func (s *gracefulServer) close() {
|
||||
if s.status == SERVER_STATUS_STOPPED {
|
||||
return
|
||||
|
||||
@ -24,38 +24,42 @@ import (
|
||||
"github.com/gogf/gf/os/gtime"
|
||||
)
|
||||
|
||||
// 默认HTTP Server处理入口,http包底层默认使用了gorutine异步处理请求,所以这里不再异步执行
|
||||
// ServeHTTP is the default handler for http request.
|
||||
// It should not create new goroutine handling the request as
|
||||
// it's called by am already created new goroutine from http.Server.
|
||||
//
|
||||
// This function also make serve implementing the interface of http.Handler.
|
||||
func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
// Max body size limit.
|
||||
if s.config.ClientMaxBodySize > 0 {
|
||||
r.Body = http.MaxBytesReader(w, r.Body, s.config.ClientMaxBodySize)
|
||||
}
|
||||
// 重写规则判断
|
||||
|
||||
// Rewrite feature checks.
|
||||
if len(s.config.Rewrites) > 0 {
|
||||
if rewrite, ok := s.config.Rewrites[r.URL.Path]; ok {
|
||||
r.URL.Path = rewrite
|
||||
}
|
||||
}
|
||||
|
||||
// 去掉末尾的"/"号
|
||||
// Remove char '/' in the tail of URI.
|
||||
if r.URL.Path != "/" {
|
||||
for len(r.URL.Path) > 0 && r.URL.Path[len(r.URL.Path)-1] == '/' {
|
||||
r.URL.Path = r.URL.Path[:len(r.URL.Path)-1]
|
||||
}
|
||||
}
|
||||
|
||||
// URI默认值
|
||||
// Default URI value if it's empty.
|
||||
if r.URL.Path == "" {
|
||||
r.URL.Path = "/"
|
||||
}
|
||||
|
||||
// 创建请求处理对象
|
||||
// Create a new request object.
|
||||
request := newRequest(s, r, w)
|
||||
|
||||
defer func() {
|
||||
// 设置请求完成时间
|
||||
request.LeaveTime = gtime.TimestampMilli()
|
||||
// error log
|
||||
// error log handling.
|
||||
if request.error != nil {
|
||||
s.handleErrorLog(request.error, request)
|
||||
} else {
|
||||
@ -64,18 +68,20 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
s.handleErrorLog(gerror.Newf("%v", exception), request)
|
||||
}
|
||||
}
|
||||
// access log
|
||||
// access log handling.
|
||||
s.handleAccessLog(request)
|
||||
// 关闭当前Session,并更新会话超时时间
|
||||
// Close the session, which automatically update the TTL
|
||||
// of the session if it exists.
|
||||
request.Session.Close()
|
||||
}()
|
||||
|
||||
// ============================================================
|
||||
// 优先级控制:
|
||||
// 静态文件 > 动态服务 > 静态目录
|
||||
// Priority:
|
||||
// Static File > Dynamic Service > Static Directory
|
||||
// ============================================================
|
||||
|
||||
// 优先执行静态文件检索(检测是否存在对应的静态文件,包括index files处理)
|
||||
// Search the static file with most high priority,
|
||||
// which also handle the index files feature.
|
||||
if s.config.FileServerEnabled {
|
||||
request.StaticFile = s.searchStaticFile(r.URL.Path)
|
||||
if request.StaticFile != nil {
|
||||
@ -83,29 +89,29 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
// 动态服务检索
|
||||
// Search the dynamic service handler.
|
||||
request.handlers, request.hasHookHandler, request.hasServeHandler = s.getHandlersWithCache(request)
|
||||
|
||||
// 判断最终对该请求提供的服务方式
|
||||
// Check the service type static or dynamic for current request.
|
||||
if request.StaticFile != nil && request.StaticFile.IsDir && request.hasServeHandler {
|
||||
request.isFileRequest = false
|
||||
}
|
||||
|
||||
// 事件 - BeforeServe
|
||||
// HOOK - BeforeServe
|
||||
s.callHookHandler(HOOK_BEFORE_SERVE, request)
|
||||
|
||||
// 执行静态文件服务/回调控制器/执行对象/方法
|
||||
// Core serving handling.
|
||||
if !request.IsExited() {
|
||||
if request.isFileRequest {
|
||||
// 静态服务
|
||||
// Static file service.
|
||||
s.serveFile(request, request.StaticFile)
|
||||
} else {
|
||||
if len(request.handlers) > 0 {
|
||||
// 动态服务
|
||||
// Dynamic service.
|
||||
request.Middleware.Next()
|
||||
} else {
|
||||
if request.StaticFile != nil && request.StaticFile.IsDir {
|
||||
// 静态目录
|
||||
// Serve the directory.
|
||||
s.serveFile(request, request.StaticFile)
|
||||
} else {
|
||||
if len(request.Response.Header()) == 0 &&
|
||||
@ -118,12 +124,12 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
// 事件 - AfterServe
|
||||
// HOOK - AfterServe
|
||||
if !request.IsExited() {
|
||||
s.callHookHandler(HOOK_AFTER_SERVE, request)
|
||||
}
|
||||
|
||||
// 事件 - BeforeOutput
|
||||
// HOOK - BeforeOutput
|
||||
if !request.IsExited() {
|
||||
s.callHookHandler(HOOK_BEFORE_OUTPUT, request)
|
||||
}
|
||||
@ -146,15 +152,16 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
// 设置Session Id到Cookie中
|
||||
// Automatically set the session id to cookie
|
||||
// if it creates a new session id in this request.
|
||||
if request.Session.IsDirty() && request.Session.Id() != request.GetSessionId() {
|
||||
request.Cookie.SetSessionId(request.Session.Id())
|
||||
}
|
||||
// 输出Cookie
|
||||
// Output the cookie content to client.
|
||||
request.Cookie.Output()
|
||||
// 输出缓冲区
|
||||
// Output the buffer content to client.
|
||||
request.Response.Output()
|
||||
// 事件 - AfterOutput
|
||||
// HOOK - AfterOutput
|
||||
if !request.IsExited() {
|
||||
s.callHookHandler(HOOK_AFTER_OUTPUT, request)
|
||||
}
|
||||
@ -222,9 +229,10 @@ func (s *Server) searchStaticFile(uri string) *StaticFile {
|
||||
return nil
|
||||
}
|
||||
|
||||
// http server静态文件处理,path可以为相对路径也可以为绝对路径
|
||||
// serveFile serves the static file for client.
|
||||
// The optional parameter <allowIndex> specifies if allowing directory listing if <f> is directory.
|
||||
func (s *Server) serveFile(r *Request, f *StaticFile, allowIndex ...bool) {
|
||||
// 使用资源文件
|
||||
// Use resource file from memory.
|
||||
if f.File != nil {
|
||||
if f.IsDir {
|
||||
if s.config.IndexFolder || (len(allowIndex) > 0 && allowIndex[0]) {
|
||||
@ -239,7 +247,7 @@ func (s *Server) serveFile(r *Request, f *StaticFile, allowIndex ...bool) {
|
||||
}
|
||||
return
|
||||
}
|
||||
// 使用磁盘文件
|
||||
// Use file from dist.
|
||||
file, err := os.Open(f.Path)
|
||||
if err != nil {
|
||||
r.Response.WriteStatus(http.StatusForbidden)
|
||||
@ -264,7 +272,7 @@ func (s *Server) serveFile(r *Request, f *StaticFile, allowIndex ...bool) {
|
||||
}
|
||||
}
|
||||
|
||||
// 显示目录列表
|
||||
// listDir lists the sub files of specified directory as HTML content to client.
|
||||
func (s *Server) listDir(r *Request, f http.File) {
|
||||
files, err := f.Readdir(-1)
|
||||
if err != nil {
|
||||
|
||||
@ -17,7 +17,7 @@ func (s *Server) Logger() *glog.Logger {
|
||||
return s.config.Logger
|
||||
}
|
||||
|
||||
// 处理服务错误信息,主要是panic,http请求的status由access log进行管理
|
||||
// handleAccessLog handles the access logging for server.
|
||||
func (s *Server) handleAccessLog(r *Request) {
|
||||
if !s.IsAccessLogEnabled() {
|
||||
return
|
||||
@ -37,14 +37,13 @@ func (s *Server) handleAccessLog(r *Request) {
|
||||
)
|
||||
}
|
||||
|
||||
// 处理服务错误信息,主要是panic,http请求的status由access log进行管理
|
||||
// handleErrorLog handles the error logging for server.
|
||||
func (s *Server) handleErrorLog(err error, r *Request) {
|
||||
// 错误输出默认是开启的
|
||||
// It does nothing if error logging is custom disabled.
|
||||
if !s.IsErrorLogEnabled() {
|
||||
return
|
||||
}
|
||||
|
||||
// 错误日志信息
|
||||
scheme := "http"
|
||||
if r.TLS != nil {
|
||||
scheme = "https"
|
||||
|
||||
@ -11,7 +11,7 @@ import (
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// 绑定指定的hook回调函数, pattern参数同BindHandler,支持命名路由;hook参数的值由ghttp server设定,参数不区分大小写
|
||||
// BindHookHandler registers handler for specified hook.
|
||||
func (s *Server) BindHookHandler(pattern string, hook string, handler HandlerFunc) {
|
||||
s.doBindHookHandler(pattern, hook, handler, "")
|
||||
}
|
||||
@ -26,23 +26,22 @@ func (s *Server) doBindHookHandler(pattern string, hook string, handler HandlerF
|
||||
})
|
||||
}
|
||||
|
||||
// 通过map批量绑定回调函数
|
||||
func (s *Server) BindHookHandlerByMap(pattern string, hookMap map[string]HandlerFunc) {
|
||||
for k, v := range hookMap {
|
||||
s.BindHookHandler(pattern, k, v)
|
||||
}
|
||||
}
|
||||
|
||||
// 事件回调处理,内部使用了缓存处理.
|
||||
// 并按照指定hook回调函数的优先级及注册顺序进行调用
|
||||
// callHookHandler calls the hook handler by their registered sequences.
|
||||
func (s *Server) callHookHandler(hook string, r *Request) {
|
||||
hookItems := r.getHookHandlers(hook)
|
||||
if len(hookItems) > 0 {
|
||||
// 备份原有的router变量
|
||||
// Backup the old router variable map.
|
||||
oldRouterMap := r.routerMap
|
||||
for _, item := range hookItems {
|
||||
r.routerMap = item.values
|
||||
// 不使用hook的router对象,保留路由注册服务的router对象,不能覆盖
|
||||
// DO NOT USE the router of the hook handler,
|
||||
// which can overwrite the router of serving handler.
|
||||
// r.Router = item.handler.router
|
||||
if err := s.niceCallHookHandler(item.handler.itemFunc, r); err != nil {
|
||||
switch err {
|
||||
@ -58,12 +57,12 @@ func (s *Server) callHookHandler(hook string, r *Request) {
|
||||
}
|
||||
}
|
||||
}
|
||||
// 恢复原有的router变量
|
||||
// Restore the old router variable map.
|
||||
r.routerMap = oldRouterMap
|
||||
}
|
||||
}
|
||||
|
||||
// 获得当前请求,指定类型的的钩子函数列表
|
||||
// getHookHandlers retrieves and returns the hook handlers of specified hook.
|
||||
func (r *Request) getHookHandlers(hook string) []*handlerParsedItem {
|
||||
if !r.hasHookHandler {
|
||||
return nil
|
||||
@ -79,7 +78,9 @@ func (r *Request) getHookHandlers(hook string) []*handlerParsedItem {
|
||||
return parsedItems
|
||||
}
|
||||
|
||||
// 友好地调用方法
|
||||
// niceCallHookHandler nicely calls the hook handler function,
|
||||
// which means it automatically catches and returns the possible panic error to
|
||||
// avoid goroutine crash.
|
||||
func (s *Server) niceCallHookHandler(f HandlerFunc, r *Request) (err interface{}) {
|
||||
defer func() {
|
||||
err = recover()
|
||||
|
||||
@ -8,4 +8,5 @@ package ghttp
|
||||
|
||||
import "github.com/gogf/gf/os/gsession"
|
||||
|
||||
// Session is actually a alias of gsession.Session.
|
||||
type Session = gsession.Session
|
||||
|
||||
@ -8,6 +8,8 @@ package ghttp
|
||||
|
||||
import "github.com/gorilla/websocket"
|
||||
|
||||
// WebSocket wraps the underlying websocket connection
|
||||
// and provides convenient functions.
|
||||
type WebSocket struct {
|
||||
*websocket.Conn
|
||||
}
|
||||
|
||||
@ -431,7 +431,7 @@ func (c *memCache) syncEventAndClearExpired() {
|
||||
}
|
||||
|
||||
// clearByKey deletes the key-value pair with given <key>.
|
||||
// The parameter <force> specifies whether doing this deleting forcedly.
|
||||
// The parameter <force> specifies whether doing this deleting forcibly.
|
||||
func (c *memCache) clearByKey(key interface{}, force ...bool) {
|
||||
c.dataMu.Lock()
|
||||
// Doubly check before really deleting it from cache.
|
||||
|
||||
Reference in New Issue
Block a user