1
0
mirror of https://github.com/astaxie/beego.git synced 2024-11-25 17:20:55 +00:00

beego: improve performance

This commit is contained in:
astaxie 2014-06-11 01:11:32 +08:00
parent 675643c68d
commit 6809c97611
3 changed files with 51 additions and 45 deletions

View File

@ -379,6 +379,10 @@ func initBeforeHttpRun() {
middleware.VERSION = VERSION middleware.VERSION = VERSION
middleware.AppName = AppName middleware.AppName = AppName
middleware.RegisterErrorHandler() middleware.RegisterErrorHandler()
for u, _ := range StaticDir {
Get(u, serverStaticRouter)
}
} }
// this function is for test package init // this function is for test package init

View File

@ -43,7 +43,17 @@ const (
var ( var (
// supported http methods. // supported http methods.
HTTPMETHOD = []string{"get", "post", "put", "delete", "patch", "options", "head", "trace", "connect"} HTTPMETHOD = map[string]string{
"GET": "GET",
"POST": "POST",
"PUT": "PUT",
"DELETE": "DELETE",
"PATCH": "PATCH",
"OPTIONS": "OPTIONS",
"HEAD": "HEAD",
"TRACE": "TRACE",
"CONNECT": "CONNECT",
}
// these beego.Controller's methods shouldn't reflect to AutoRouter // these beego.Controller's methods shouldn't reflect to AutoRouter
exceptMethod = []string{"Init", "Prepare", "Finish", "Render", "RenderString", exceptMethod = []string{"Init", "Prepare", "Finish", "Render", "RenderString",
"RenderBytes", "Redirect", "Abort", "StopRun", "UrlFor", "ServeJson", "ServeJsonp", "RenderBytes", "Redirect", "Abort", "StopRun", "UrlFor", "ServeJson", "ServeJsonp",
@ -106,9 +116,9 @@ func (p *ControllerRegistor) Add(pattern string, c ControllerInterface, mappingM
} }
comma := strings.Split(colon[0], ",") comma := strings.Split(colon[0], ",")
for _, m := range comma { for _, m := range comma {
if m == "*" || utils.InSlice(strings.ToLower(m), HTTPMETHOD) { if _, ok := HTTPMETHOD[strings.ToUpper(m)]; m == "*" || ok {
if val := reflectVal.MethodByName(colon[1]); val.IsValid() { if val := reflectVal.MethodByName(colon[1]); val.IsValid() {
methods[strings.ToLower(m)] = colon[1] methods[strings.ToUpper(m)] = colon[1]
} else { } else {
panic(colon[1] + " method doesn't exist in the controller " + t.Name()) panic(colon[1] + " method doesn't exist in the controller " + t.Name())
} }
@ -271,7 +281,7 @@ func (p *ControllerRegistor) Any(pattern string, f FilterFunc) {
// ctx.Output.Body("hello world") // ctx.Output.Body("hello world")
// }) // })
func (p *ControllerRegistor) AddMethod(method, pattern string, f FilterFunc) { func (p *ControllerRegistor) AddMethod(method, pattern string, f FilterFunc) {
if method != "*" && !utils.InSlice(strings.ToLower(method), HTTPMETHOD) { if _, ok := HTTPMETHOD[strings.ToUpper(method)]; method != "*" && !ok {
panic("not support http method: " + method) panic("not support http method: " + method)
} }
route := &controllerInfo{} route := &controllerInfo{}
@ -284,7 +294,7 @@ func (p *ControllerRegistor) AddMethod(method, pattern string, f FilterFunc) {
methods[val] = val methods[val] = val
} }
} else { } else {
methods[method] = method methods[strings.ToUpper(method)] = strings.ToUpper(method)
} }
route.methods = methods route.methods = methods
for k, _ := range methods { for k, _ := range methods {
@ -417,8 +427,8 @@ func (p *ControllerRegistor) geturl(t *Tree, url, controllName, methodName strin
if c, ok := t.leaf.runObject.(*controllerInfo); ok { if c, ok := t.leaf.runObject.(*controllerInfo); ok {
if c.routerType == routerTypeBeego && c.controllerType.Name() == controllName { if c.routerType == routerTypeBeego && c.controllerType.Name() == controllName {
find := false find := false
if utils.InSlice(strings.ToLower(methodName), HTTPMETHOD) { if _, ok := HTTPMETHOD[strings.ToUpper(methodName)]; ok {
if m, ok := c.methods[strings.ToLower(methodName)]; ok && m != methodName { if m, ok := c.methods[strings.ToUpper(methodName)]; ok && m != strings.ToUpper(methodName) {
return false, "" return false, ""
} else if m, ok = c.methods["*"]; ok && m != methodName { } else if m, ok = c.methods["*"]; ok && m != methodName {
return false, "" return false, ""
@ -508,8 +518,6 @@ func (p *ControllerRegistor) geturl(t *Tree, url, controllName, methodName strin
func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request) { func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
defer p.recoverPanic(rw, r) defer p.recoverPanic(rw, r)
starttime := time.Now() starttime := time.Now()
requestPath := r.URL.Path
method := strings.ToLower(r.Method)
var runrouter reflect.Type var runrouter reflect.Type
var findrouter bool var findrouter bool
var runMethod string var runMethod string
@ -559,12 +567,12 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request)
}() }()
} }
if !utils.InSlice(method, HTTPMETHOD) { if _, ok := HTTPMETHOD[r.Method]; !ok {
http.Error(w, "Method Not Allowed", 405) http.Error(w, "Method Not Allowed", 405)
goto Admin goto Admin
} }
if !context.Input.IsGet() && !context.Input.IsHead() { if r.Method != "GET" && r.Method != "HEAD" {
if CopyRequestBody && !context.Input.IsUpload() { if CopyRequestBody && !context.Input.IsUpload() {
context.Input.CopyBody() context.Input.CopyBody()
} }
@ -575,11 +583,6 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request)
goto Admin goto Admin
} }
//static file server
if serverStaticRouter(context) {
goto Admin
}
if context.Input.RunController != nil && context.Input.RunMethod != "" { if context.Input.RunController != nil && context.Input.RunMethod != "" {
findrouter = true findrouter = true
runMethod = context.Input.RunMethod runMethod = context.Input.RunMethod
@ -587,8 +590,8 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request)
} }
if !findrouter { if !findrouter {
if t, ok := p.routers[method]; ok { if t, ok := p.routers[r.Method]; ok {
runObject, p := t.Match(requestPath) runObject, p := t.Match(r.URL.Path)
if r, ok := runObject.(*controllerInfo); ok { if r, ok := runObject.(*controllerInfo); ok {
routerInfo = r routerInfo = r
findrouter = true findrouter = true
@ -618,7 +621,7 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request)
isRunable := false isRunable := false
if routerInfo != nil { if routerInfo != nil {
if routerInfo.routerType == routerTypeRESTFul { if routerInfo.routerType == routerTypeRESTFul {
if _, ok := routerInfo.methods[strings.ToLower(r.Method)]; ok { if _, ok := routerInfo.methods[r.Method]; ok {
isRunable = true isRunable = true
routerInfo.runfunction(context) routerInfo.runfunction(context)
} else { } else {
@ -630,19 +633,19 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request)
routerInfo.handler.ServeHTTP(rw, r) routerInfo.handler.ServeHTTP(rw, r)
} else { } else {
runrouter = routerInfo.controllerType runrouter = routerInfo.controllerType
method := strings.ToLower(r.Method) method := r.Method
if method == "post" && strings.ToLower(context.Input.Query("_method")) == "put" { if r.Method == "POST" && context.Input.Query("_method") == "PUT" {
method = "put" method = "PUT"
} }
if method == "post" && strings.ToLower(context.Input.Query("_method")) == "delete" { if r.Method == "POST" && context.Input.Query("_method") == "DELETE" {
method = "delete" method = "DELETE"
} }
if m, ok := routerInfo.methods[method]; ok { if m, ok := routerInfo.methods[method]; ok {
runMethod = m runMethod = m
} else if m, ok = routerInfo.methods["*"]; ok { } else if m, ok = routerInfo.methods["*"]; ok {
runMethod = m runMethod = m
} else { } else {
runMethod = strings.Title(method) runMethod = method
} }
} }
} }
@ -676,19 +679,19 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request)
if !w.started { if !w.started {
//exec main logic //exec main logic
switch runMethod { switch runMethod {
case "Get": case "GET":
execController.Get() execController.Get()
case "Post": case "POST":
execController.Post() execController.Post()
case "Delete": case "DELETE":
execController.Delete() execController.Delete()
case "Put": case "PUT":
execController.Put() execController.Put()
case "Head": case "HEAD":
execController.Head() execController.Head()
case "Patch": case "PATCH":
execController.Patch() execController.Patch()
case "Options": case "OPTIONS":
execController.Options() execController.Options()
default: default:
if !execController.HandlerFunc(runMethod) { if !execController.HandlerFunc(runMethod) {
@ -725,20 +728,20 @@ Admin:
timeend := time.Since(starttime) timeend := time.Since(starttime)
//admin module record QPS //admin module record QPS
if EnableAdmin { if EnableAdmin {
if FilterMonitorFunc(r.Method, requestPath, timeend) { if FilterMonitorFunc(r.Method, r.URL.Path, timeend) {
if runrouter != nil { if runrouter != nil {
go toolbox.StatisticsMap.AddStatistics(r.Method, requestPath, runrouter.Name(), timeend) go toolbox.StatisticsMap.AddStatistics(r.Method, r.URL.Path, runrouter.Name(), timeend)
} else { } else {
go toolbox.StatisticsMap.AddStatistics(r.Method, requestPath, "", timeend) go toolbox.StatisticsMap.AddStatistics(r.Method, r.URL.Path, "", timeend)
} }
} }
} }
if RunMode == "dev" { if RunMode == "dev" {
if findrouter { if findrouter {
Info("beego: router defined " + routerInfo.pattern + " " + requestPath + " +" + timeend.String()) Info("beego: router defined " + routerInfo.pattern + " " + r.URL.Path + " +" + timeend.String())
} else { } else {
Info("beego:" + requestPath + " 404" + " +" + timeend.String()) Info("beego:" + r.URL.Path + " 404" + " +" + timeend.String())
} }
} }
} }

View File

@ -18,7 +18,7 @@ import (
"github.com/astaxie/beego/utils" "github.com/astaxie/beego/utils"
) )
func serverStaticRouter(ctx *context.Context) bool { func serverStaticRouter(ctx *context.Context) {
requestPath := path.Clean(ctx.Input.Request.URL.Path) requestPath := path.Clean(ctx.Input.Request.URL.Path)
for prefix, staticDir := range StaticDir { for prefix, staticDir := range StaticDir {
if len(prefix) == 0 { if len(prefix) == 0 {
@ -28,7 +28,7 @@ func serverStaticRouter(ctx *context.Context) bool {
file := path.Join(staticDir, requestPath) file := path.Join(staticDir, requestPath)
if utils.FileExists(file) { if utils.FileExists(file) {
http.ServeFile(ctx.ResponseWriter, ctx.Request, file) http.ServeFile(ctx.ResponseWriter, ctx.Request, file)
return true return
} }
} }
if strings.HasPrefix(requestPath, prefix) { if strings.HasPrefix(requestPath, prefix) {
@ -37,7 +37,7 @@ func serverStaticRouter(ctx *context.Context) bool {
} }
if requestPath == prefix && prefix[len(prefix)-1] != '/' { if requestPath == prefix && prefix[len(prefix)-1] != '/' {
http.Redirect(ctx.ResponseWriter, ctx.Request, requestPath+"/", 302) http.Redirect(ctx.ResponseWriter, ctx.Request, requestPath+"/", 302)
return true return
} }
file := path.Join(staticDir, requestPath[len(prefix):]) file := path.Join(staticDir, requestPath[len(prefix):])
finfo, err := os.Stat(file) finfo, err := os.Stat(file)
@ -46,12 +46,12 @@ func serverStaticRouter(ctx *context.Context) bool {
Warn(err) Warn(err)
} }
http.NotFound(ctx.ResponseWriter, ctx.Request) http.NotFound(ctx.ResponseWriter, ctx.Request)
return true return
} }
//if the request is dir and DirectoryIndex is false then //if the request is dir and DirectoryIndex is false then
if finfo.IsDir() && !DirectoryIndex { if finfo.IsDir() && !DirectoryIndex {
middleware.Exception("403", ctx.ResponseWriter, ctx.Request, "403 Forbidden") middleware.Exception("403", ctx.ResponseWriter, ctx.Request, "403 Forbidden")
return true return
} }
//This block obtained from (https://github.com/smithfox/beego) - it should probably get merged into astaxie/beego after a pull request //This block obtained from (https://github.com/smithfox/beego) - it should probably get merged into astaxie/beego after a pull request
@ -73,7 +73,7 @@ func serverStaticRouter(ctx *context.Context) bool {
memzipfile, err := openMemZipFile(file, contentEncoding) memzipfile, err := openMemZipFile(file, contentEncoding)
if err != nil { if err != nil {
return true return
} }
if contentEncoding == "gzip" { if contentEncoding == "gzip" {
@ -89,8 +89,7 @@ func serverStaticRouter(ctx *context.Context) bool {
} else { } else {
http.ServeFile(ctx.ResponseWriter, ctx.Request, file) http.ServeFile(ctx.ResponseWriter, ctx.Request, file)
} }
return true return
} }
} }
return false
} }