mirror of
https://gitee.com/johng/gf
synced 2026-06-06 16:21:40 +08:00
improve gerror, ghttp for error stack logging; improve custom view feature for ghttp.Request
This commit is contained in:
@ -1,17 +1,10 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/text/gstr"
|
||||
)
|
||||
|
||||
func main() {
|
||||
//b := make([]byte, 10)
|
||||
r := bytes.NewBuffer(make([]byte, 1))
|
||||
|
||||
n, err := r.Write([]byte("12345"))
|
||||
|
||||
fmt.Println(n)
|
||||
fmt.Println(err)
|
||||
fmt.Println(r.String())
|
||||
fmt.Println(gstr.CamelCase("/auth/routerName.html"))
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@ language: go
|
||||
go:
|
||||
- "1.11.x"
|
||||
- "1.12.x"
|
||||
- "1.13.x"
|
||||
|
||||
branches:
|
||||
only:
|
||||
|
||||
@ -324,6 +324,7 @@ func Test_Model_Safe(t *testing.T) {
|
||||
md1 := db.Table(table).Where("id>", 0).Safe()
|
||||
md2 := md1.Where("id in (?)", g.Slice{1, 3})
|
||||
md3 := md1.Where("id in (?)", g.Slice{4, 5, 6})
|
||||
|
||||
// 1,3
|
||||
count, err := md2.Count()
|
||||
gtest.Assert(err, nil)
|
||||
|
||||
@ -22,7 +22,7 @@ type Error struct {
|
||||
}
|
||||
|
||||
const (
|
||||
gFILTER_KEY = "/errors/gerror/gerror"
|
||||
gFILTER_KEY = "github.com/gogf/gf/"
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
@ -8,6 +8,8 @@ package ghttp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/os/gview"
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
"io/ioutil"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
@ -21,54 +23,53 @@ import (
|
||||
"github.com/gogf/gf/text/gregex"
|
||||
)
|
||||
|
||||
// 请求对象
|
||||
// Request is the context object for a request.
|
||||
type Request struct {
|
||||
*http.Request
|
||||
Id int // 请求ID(当前Server对象唯一)
|
||||
Server *Server // 请求关联的服务器对象
|
||||
Cookie *Cookie // 与当前请求绑定的Cookie对象(并发安全)
|
||||
Session *gsession.Session // 与当前请求绑定的Session对象(并发安全)
|
||||
Response *Response // 对应请求的返回数据操作对象
|
||||
Router *Router // 匹配到的路由对象
|
||||
EnterTime int64 // 请求进入时间(微秒)
|
||||
LeaveTime int64 // 请求完成时间(微秒)
|
||||
Middleware *Middleware // 中间件功能调用对象
|
||||
handlers []*handlerParsedItem // 请求执行服务函数列表(包含中间件、路由函数、钩子函数)
|
||||
handlerIndex int // 当前执行函数的索引号
|
||||
hasHookHandler bool // 是否检索到钩子函数(用于请求时提高钩子函数功能启用判断效率)
|
||||
hasServeHandler bool // 是否检索到服务函数
|
||||
parsedGet bool // GET参数是否已经解析
|
||||
parsedPut bool // PUT参数是否已经解析
|
||||
parsedPost bool // POST参数是否已经解析
|
||||
parsedDelete bool // DELETE参数是否已经解析
|
||||
parsedRaw bool // 原始参数是否已经解析
|
||||
parsedForm bool // 是否已调用r.ParseMultipartForm
|
||||
getMap map[string]interface{} // GET解析参数
|
||||
putMap map[string]interface{} // PUT解析参数
|
||||
postMap map[string]interface{} // POST解析参数
|
||||
deleteMap map[string]interface{} // DELETE解析参数
|
||||
routerMap map[string]interface{} // 路由解析参数
|
||||
rawMap map[string]interface{} // 原始数据参数
|
||||
error error // 当前请求执行错误
|
||||
exit bool // 是否退出当前请求流程执行
|
||||
params map[string]interface{} // 开发者自定义参数(请求流程中有效)
|
||||
parsedHost string // 解析过后不带端口号的服务器域名名称
|
||||
clientIp string // 解析过后的客户端IP地址
|
||||
rawContent []byte // 客户端提交的原始参数
|
||||
isFileRequest bool // 是否为静态文件请求(非服务请求,当静态文件存在时,优先级会被服务请求高,被识别为文件请求)
|
||||
Server *Server // Parent server.
|
||||
Cookie *Cookie // Cookie.
|
||||
Session *gsession.Session // Session.
|
||||
Response *Response // Corresponding Response of this request.
|
||||
Router *Router // Matched Router for this request. Note that it's only available in HTTP handler, not in HOOK or MiddleWare.
|
||||
EnterTime int64 // Request starting time in microseconds.
|
||||
LeaveTime int64 // Request ending time in microseconds.
|
||||
Middleware *Middleware // The middleware manager.
|
||||
handlers []*handlerParsedItem // All matched handlers containing handler, hook and middleware for this request .
|
||||
handlerIndex int // Index number for executing sequence purpose of handlers.
|
||||
hasHookHandler bool // A bool marking whether there's hook handler in the handlers for performance purpose.
|
||||
hasServeHandler bool // A bool marking whether there's serving handler in the handlers for performance purpose.
|
||||
parsedGet bool // A bool marking whether the GET parameters parsed.
|
||||
parsedPut bool // A bool marking whether the PUT parameters parsed.
|
||||
parsedPost bool // A bool marking whether the POST parameters parsed.
|
||||
parsedDelete bool // A bool marking whether the DELETE parameters parsed.
|
||||
parsedRaw bool // A bool marking whether the request body parsed.
|
||||
parsedForm bool // A bool marking whether r.ParseMultipartForm called.
|
||||
getMap map[string]interface{} // GET parameters map, which might be nil if there're no GET parameters.
|
||||
putMap map[string]interface{} // PUT parameters map, which might be nil if there're no PUT parameters.
|
||||
postMap map[string]interface{} // POST parameters map, which might be nil if there're no POST parameters.
|
||||
deleteMap map[string]interface{} // DELETE parameters map, which might be nil if there're no DELETE parameters.
|
||||
routerMap map[string]interface{} // Router parameters map, which might be nil if there're no router parameters.
|
||||
rawMap map[string]interface{} // Body parameters map, which might be nil if there're no body content.
|
||||
error error // Current executing error of the request.
|
||||
exit bool // A bool marking whether current request is exited.
|
||||
params map[string]interface{} // Custom parameters.
|
||||
parsedHost string // The parsed host name for current host used by GetHost function.
|
||||
clientIp string // The parsed client ip for current host used by GetClientIp function.
|
||||
rawContent []byte // Request body content.
|
||||
isFileRequest bool // A bool marking whether current request is file serving.
|
||||
view *gview.View // Custom template view engine object for this response.
|
||||
viewParams gview.Params // Custom template view variables for this response.
|
||||
}
|
||||
|
||||
// 创建一个Request对象
|
||||
// newRequest creates and returns a new request object.
|
||||
func newRequest(s *Server, r *http.Request, w http.ResponseWriter) *Request {
|
||||
request := &Request{
|
||||
routerMap: make(map[string]interface{}),
|
||||
Id: s.servedCount.Add(1),
|
||||
Server: s,
|
||||
Request: r,
|
||||
Response: newResponse(s, w),
|
||||
EnterTime: gtime.Microsecond(),
|
||||
}
|
||||
// 会话处理
|
||||
request.Cookie = GetCookie(request)
|
||||
request.Session = s.sessionManager.New(request.GetSessionId())
|
||||
request.Response.Request = request
|
||||
@ -78,7 +79,9 @@ func newRequest(s *Server, r *http.Request, w http.ResponseWriter) *Request {
|
||||
return request
|
||||
}
|
||||
|
||||
// 获取Web Socket连接对象(如果是非WS请求会失败,注意检查返回的error结果)
|
||||
// WebSocket upgrades current request as a websocket request.
|
||||
// It returns a new WebSocket object if success, or the error if failure.
|
||||
// Note that the request should be a websocket request, or it will surely fail upgrading.
|
||||
func (r *Request) WebSocket() (*WebSocket, error) {
|
||||
if conn, err := wsUpgrader.Upgrade(r.Response.Writer, r.Request, nil); err == nil {
|
||||
return &WebSocket{
|
||||
@ -89,18 +92,19 @@ func (r *Request) WebSocket() (*WebSocket, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// Get是GetRequest方法的别名,用于获得指定名称的参数值,注意键值可能是字符串、数组、Map类型。
|
||||
// 大多数场景下,你可能需要的是 GetString/GetVar。
|
||||
// Get retrieves and returns field value with given name <key> from request.
|
||||
// The parameter <def> specifies the default returned value if value of field <key> is not found.
|
||||
func (r *Request) Get(key string, def ...interface{}) interface{} {
|
||||
return r.GetRequest(key, def...)
|
||||
}
|
||||
|
||||
// 建议都用该参数替代参数获取
|
||||
// GetVar retrieves and returns field value with given name <key> from request as a gvar.Var.
|
||||
// The parameter <def> specifies the default returned value if value of field <key> is not found.
|
||||
func (r *Request) GetVar(key string, def ...interface{}) *gvar.Var {
|
||||
return r.GetRequestVar(key, def...)
|
||||
}
|
||||
|
||||
// 获取原始请求输入二进制。
|
||||
// GetRaw retrieves and returns request body content as bytes.
|
||||
func (r *Request) GetRaw() []byte {
|
||||
if r.rawContent == nil {
|
||||
r.rawContent, _ = ioutil.ReadAll(r.Body)
|
||||
@ -108,12 +112,13 @@ func (r *Request) GetRaw() []byte {
|
||||
return r.rawContent
|
||||
}
|
||||
|
||||
// 获取原始请求输入字符串。
|
||||
// GetRawString retrieves and returns request body content as string.
|
||||
func (r *Request) GetRawString() string {
|
||||
return string(r.GetRaw())
|
||||
return gconv.UnsafeBytesToStr(r.GetRaw())
|
||||
}
|
||||
|
||||
// 获取原始json请求输入字符串,并解析为json对象
|
||||
// GetJson parses current request content as JSON format, and returns the JSON object.
|
||||
// Note that the request content is read from request BODY, not from any field of FORM.
|
||||
func (r *Request) GetJson() (*gjson.Json, error) {
|
||||
return gjson.LoadJson(r.GetRaw())
|
||||
}
|
||||
@ -186,34 +191,35 @@ func (r *Request) GetMapStrStr(def ...map[string]interface{}) map[string]string
|
||||
return r.GetRequestMapStrStr(def...)
|
||||
}
|
||||
|
||||
// 将所有的request参数映射到struct属性上,参数pointer应当为一个struct对象的指针,
|
||||
// mapping为非必需参数,自定义参数与属性的映射关系
|
||||
// GetToStruct maps all request variables to a struct object.
|
||||
// The parameter <pointer> should be a pointer to a struct object.
|
||||
// More details please refer to: gconv.StructDeep.
|
||||
func (r *Request) GetToStruct(pointer interface{}, mapping ...map[string]string) error {
|
||||
return r.GetRequestToStruct(pointer, mapping...)
|
||||
}
|
||||
|
||||
// 仅退出当前逻辑执行函数, 如:服务函数、HOOK函数
|
||||
// Exit exits executing of current HTTP handler.
|
||||
func (r *Request) Exit() {
|
||||
panic(gEXCEPTION_EXIT)
|
||||
}
|
||||
|
||||
// 退出当前请求执行,后续所有的服务逻辑流程(包括其他的HOOK)将不会执行
|
||||
// ExitAll exits executing of current and following HTTP handlers.
|
||||
func (r *Request) ExitAll() {
|
||||
r.exit = true
|
||||
panic(gEXCEPTION_EXIT_ALL)
|
||||
}
|
||||
|
||||
// 仅针对HOOK执行,默认情况下HOOK会按照优先级进行调用,当使用ExitHook后当前类型的后续HOOK将不会被调用
|
||||
// ExitHook exits executing of current and following HTTP HOOK handlers.
|
||||
func (r *Request) ExitHook() {
|
||||
panic(gEXCEPTION_EXIT_HOOK)
|
||||
}
|
||||
|
||||
// 判断当前请求是否停止执行
|
||||
// IsExited checks and returns whether current request is exited.
|
||||
func (r *Request) IsExited() bool {
|
||||
return r.exit
|
||||
}
|
||||
|
||||
// 获取请求的服务端IP/域名
|
||||
// GetHost returns current request host name, which might be a domain or an IP without port.
|
||||
func (r *Request) GetHost() string {
|
||||
if len(r.parsedHost) == 0 {
|
||||
array, _ := gregex.MatchString(`(.+):(\d+)`, r.Host)
|
||||
@ -226,7 +232,7 @@ func (r *Request) GetHost() string {
|
||||
return r.parsedHost
|
||||
}
|
||||
|
||||
// 根据服务端配置解析multipart.Form
|
||||
// parseMultipartForm parses and returns the form as multipart form.
|
||||
func (r *Request) parseMultipartForm() *multipart.Form {
|
||||
if !r.parsedForm {
|
||||
r.ParseMultipartForm(r.Server.config.FormParsingMemory)
|
||||
@ -235,12 +241,13 @@ func (r *Request) parseMultipartForm() *multipart.Form {
|
||||
return r.MultipartForm
|
||||
}
|
||||
|
||||
// 获取解析后的multipart.Form对象
|
||||
// GetMultipartForm parses and returns the form as multipart form.
|
||||
func (r *Request) GetMultipartForm() *multipart.Form {
|
||||
return r.parseMultipartForm()
|
||||
}
|
||||
|
||||
// 获取上传的文件列表
|
||||
// GetMultipartFiles returns the post files array.
|
||||
// Note that the request form should be type of multipart.
|
||||
func (r *Request) GetMultipartFiles(name string) []*multipart.FileHeader {
|
||||
form := r.GetMultipartForm()
|
||||
if form == nil {
|
||||
@ -256,17 +263,17 @@ func (r *Request) GetMultipartFiles(name string) []*multipart.FileHeader {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 判断是否为静态文件请求
|
||||
// IsFileRequest checks and returns whether current request is serving file.
|
||||
func (r *Request) IsFileRequest() bool {
|
||||
return r.isFileRequest
|
||||
}
|
||||
|
||||
// 判断是否为AJAX请求
|
||||
// IsAjaxRequest checks and returns whether current request is an AJAX request.
|
||||
func (r *Request) IsAjaxRequest() bool {
|
||||
return strings.EqualFold(r.Header.Get("X-Requested-With"), "XMLHttpRequest")
|
||||
}
|
||||
|
||||
// 获取请求的客户端IP地址
|
||||
// GetClientIp returns the client ip of this request.
|
||||
func (r *Request) GetClientIp() string {
|
||||
if len(r.clientIp) == 0 {
|
||||
if r.clientIp = r.Header.Get("X-Real-IP"); r.clientIp == "" {
|
||||
@ -281,7 +288,7 @@ func (r *Request) GetClientIp() string {
|
||||
return r.clientIp
|
||||
}
|
||||
|
||||
// 获得当前请求URL地址
|
||||
// GetUrl returns current URL of this request.
|
||||
func (r *Request) GetUrl() string {
|
||||
scheme := "http"
|
||||
if r.TLS != nil {
|
||||
@ -290,7 +297,7 @@ func (r *Request) GetUrl() string {
|
||||
return fmt.Sprintf(`%s://%s%s`, scheme, r.Host, r.URL.String())
|
||||
}
|
||||
|
||||
// 从Cookie和Header中查询SESSIONID
|
||||
// GetSessionId retrieves and returns session id from cookie or header.
|
||||
func (r *Request) GetSessionId() string {
|
||||
id := r.Cookie.GetSessionId()
|
||||
if id == "" {
|
||||
@ -299,7 +306,7 @@ func (r *Request) GetSessionId() string {
|
||||
return id
|
||||
}
|
||||
|
||||
// 获得请求来源URL地址
|
||||
// GetReferer returns referer of this request.
|
||||
func (r *Request) GetReferer() string {
|
||||
return r.Header.Get("Referer")
|
||||
}
|
||||
|
||||
44
net/ghttp/ghttp_request_view.go
Normal file
44
net/ghttp/ghttp_request_view.go
Normal file
@ -0,0 +1,44 @@
|
||||
// Copyright 2019 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 "github.com/gogf/gf/os/gview"
|
||||
|
||||
// SetView sets template view engine object for this response.
|
||||
func (r *Request) SetView(view *gview.View) {
|
||||
r.view = view
|
||||
}
|
||||
|
||||
// GetView returns the template view engine object for this response.
|
||||
func (r *Request) GetView() *gview.View {
|
||||
view := r.view
|
||||
if view == nil {
|
||||
view = r.Server.config.View
|
||||
}
|
||||
if view == nil {
|
||||
gview.Instance()
|
||||
}
|
||||
return view
|
||||
}
|
||||
|
||||
// Assigns binds multiple template variables to current request.
|
||||
func (r *Request) Assigns(data gview.Params) {
|
||||
if r.viewParams == nil {
|
||||
r.viewParams = make(gview.Params, len(data))
|
||||
}
|
||||
for k, v := range data {
|
||||
r.viewParams[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
// Assign binds a template variable to current request.
|
||||
func (r *Request) Assign(key string, value interface{}) {
|
||||
if r.viewParams == nil {
|
||||
r.viewParams = make(gview.Params)
|
||||
}
|
||||
r.viewParams[key] = value
|
||||
}
|
||||
@ -11,7 +11,6 @@ import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/os/gview"
|
||||
"net/http"
|
||||
|
||||
"github.com/gogf/gf/os/gres"
|
||||
@ -28,7 +27,6 @@ type Response struct {
|
||||
Server *Server // Parent server.
|
||||
Writer *ResponseWriter // Alias of ResponseWriter.
|
||||
Request *Request // According request.
|
||||
view *gview.View // Custom template view engine object for this response.
|
||||
}
|
||||
|
||||
// newResponse creates and returns a new Response object.
|
||||
|
||||
@ -13,23 +13,6 @@ import (
|
||||
"github.com/gogf/gf/util/gmode"
|
||||
)
|
||||
|
||||
// SetView sets template view engine object for this response.
|
||||
func (r *Response) SetView(view *gview.View) {
|
||||
r.view = view
|
||||
}
|
||||
|
||||
// GetView returns the template view engine object for this response.
|
||||
func (r *Response) GetView() *gview.View {
|
||||
view := r.view
|
||||
if view == nil {
|
||||
view = r.Server.config.View
|
||||
}
|
||||
if view == nil {
|
||||
gview.Instance()
|
||||
}
|
||||
return view
|
||||
}
|
||||
|
||||
// WriteTpl parses and responses given template file.
|
||||
// The parameter <params> specifies the template variables for parsing.
|
||||
func (r *Response) WriteTpl(tpl string, params ...gview.Params) error {
|
||||
@ -75,18 +58,18 @@ func (r *Response) WriteTplContent(content string, params ...gview.Params) error
|
||||
// ParseTpl parses given template file <tpl> with given template variables <params>
|
||||
// and returns the parsed template content.
|
||||
func (r *Response) ParseTpl(tpl string, params ...gview.Params) (string, error) {
|
||||
return r.GetView().Parse(tpl, r.buildInVars(params...))
|
||||
return r.Request.GetView().Parse(tpl, r.buildInVars(params...))
|
||||
}
|
||||
|
||||
// ParseDefault parses the default template file with params.
|
||||
func (r *Response) ParseTplDefault(params ...gview.Params) (string, error) {
|
||||
return r.GetView().ParseDefault(r.buildInVars(params...))
|
||||
return r.Request.GetView().ParseDefault(r.buildInVars(params...))
|
||||
}
|
||||
|
||||
// ParseTplContent parses given template file <file> with given template parameters <params>
|
||||
// and returns the parsed template content.
|
||||
func (r *Response) ParseTplContent(content string, params ...gview.Params) (string, error) {
|
||||
return r.GetView().ParseContent(content, r.buildInVars(params...))
|
||||
return r.Request.GetView().ParseContent(content, r.buildInVars(params...))
|
||||
}
|
||||
|
||||
// buildInVars merges build-in variables into <params> and returns the new template variables.
|
||||
@ -97,7 +80,14 @@ func (r *Response) buildInVars(params ...map[string]interface{}) map[string]inte
|
||||
} else {
|
||||
vars = make(map[string]interface{})
|
||||
}
|
||||
// 当配置文件不存在时就不赋值该模板变量,不然会报错
|
||||
// Retrieve custom template variables from request object.
|
||||
if len(r.Request.viewParams) > 0 {
|
||||
for k, v := range r.Request.viewParams {
|
||||
vars[k] = v
|
||||
}
|
||||
}
|
||||
// Note that it should assign no Config variable to template
|
||||
// if there's no configuration file.
|
||||
if c := gcfg.Instance(); c.FilePath() != "" {
|
||||
vars["Config"] = c.GetMap(".")
|
||||
}
|
||||
|
||||
@ -8,10 +8,11 @@ package ghttp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/errors/gerror"
|
||||
)
|
||||
|
||||
const (
|
||||
gPATH_FILTER_KEY = "/net/ghttp/ghttp"
|
||||
gPATH_FILTER_KEY = "github.com/gogf/gf/"
|
||||
)
|
||||
|
||||
// 处理服务错误信息,主要是panic,http请求的status由access log进行管理
|
||||
@ -23,7 +24,7 @@ func (s *Server) handleAccessLog(r *Request) {
|
||||
if r.TLS != nil {
|
||||
scheme = "https"
|
||||
}
|
||||
s.config.Logger.File(s.config.AccessLogPattern).StackWithFilter(gPATH_FILTER_KEY).Stdout(s.config.LogStdout).Printf(
|
||||
s.config.Logger.File(s.config.AccessLogPattern).Stdout(s.config.LogStdout).Printf(
|
||||
`%d "%s %s %s %s %s" %.3f, %s, "%s", "%s"`,
|
||||
r.Response.Status,
|
||||
r.Method, scheme, r.Host, r.URL.String(), r.Proto,
|
||||
@ -44,13 +45,19 @@ func (s *Server) handleErrorLog(err error, r *Request) {
|
||||
if r.TLS != nil {
|
||||
scheme = "https"
|
||||
}
|
||||
content := fmt.Sprintf(`%v, "%s %s %s %s %s"`, err, r.Method, scheme, r.Host, r.URL.String(), r.Proto)
|
||||
content += fmt.Sprintf(` %.3f`, float64(r.LeaveTime-r.EnterTime)/1000)
|
||||
content += fmt.Sprintf(`, %s, "%s", "%s"`, r.GetClientIp(), r.Referer(), r.UserAgent())
|
||||
s.config.Logger.File(s.config.AccessLogPattern).Stack(s.config.ErrorStack).Stdout(s.config.LogStdout).Errorf(
|
||||
`%v, "%s %s %s %s %s" %.3f, %s, "%s", "%s"`,
|
||||
err, r.Method, scheme, r.Host, r.URL.String(), r.Proto,
|
||||
content := fmt.Sprintf(`%d, "%s %s %s %s %s" %.3f, %s, "%s", "%s"`,
|
||||
r.Response.Status, r.Method, scheme, r.Host, r.URL.String(), r.Proto,
|
||||
float64(r.LeaveTime-r.EnterTime)/1000,
|
||||
r.GetClientIp(), r.Referer(), r.UserAgent(),
|
||||
)
|
||||
if stack := gerror.Stack(err); stack != "" {
|
||||
content += "\nStack:\n" + stack
|
||||
s.config.Logger.File(s.config.AccessLogPattern).Stack(false).Stdout(s.config.LogStdout).Error(content)
|
||||
return
|
||||
}
|
||||
s.config.Logger.File(s.config.AccessLogPattern).
|
||||
Stack(s.config.ErrorStack).
|
||||
StackWithFilter(gPATH_FILTER_KEY).
|
||||
Stdout(s.config.LogStdout).
|
||||
Errorf(content)
|
||||
}
|
||||
|
||||
@ -213,7 +213,11 @@ func (g *RouterGroup) Hook(pattern string, hook string, handler HandlerFunc) *Ro
|
||||
func (g *RouterGroup) Middleware(handlers ...HandlerFunc) *RouterGroup {
|
||||
group := g.Clone()
|
||||
for _, handler := range handlers {
|
||||
group.preBind("MIDDLEWARE", "/*", handler)
|
||||
if gstr.Contains(g.prefix, "*") {
|
||||
group.preBind("MIDDLEWARE", "/", handler)
|
||||
} else {
|
||||
group.preBind("MIDDLEWARE", "/*", handler)
|
||||
}
|
||||
}
|
||||
return group
|
||||
}
|
||||
|
||||
@ -8,7 +8,7 @@ package gview
|
||||
|
||||
import "github.com/gogf/gf/i18n/gi18n"
|
||||
|
||||
// Assign binds multiple global template variables to current view object.
|
||||
// Assigns binds multiple global template variables to current view object.
|
||||
// Note that it's not concurrent-safe, which means it would panic
|
||||
// if it's called in multiple goroutines in runtime.
|
||||
func (view *View) Assigns(data Params) {
|
||||
|
||||
Reference in New Issue
Block a user