WebServer性能细节改进

This commit is contained in:
John
2018-11-17 11:17:02 +08:00
parent b190ee9fe6
commit c89482c3d6
7 changed files with 52 additions and 34 deletions

View File

@ -8,6 +8,7 @@
package ghttp
import (
"bytes"
"gitee.com/johng/gf/g/os/gfile"
"net/http"
"gitee.com/johng/gf/g/util/gconv"
@ -32,7 +33,7 @@ func newResponse(s *Server, w http.ResponseWriter) *Response {
ResponseWriter : ResponseWriter {
ResponseWriter : w,
Status : http.StatusOK,
buffer : make([]byte, 0),
buffer : bytes.NewBuffer(nil),
},
}
r.Writer = &r.ResponseWriter
@ -48,10 +49,11 @@ func (r *Response) Write(content ... interface{}) {
switch v.(type) {
case []byte:
// 如果是二进制数据,那么返回二进制数据
r.buffer = append(r.buffer, gconv.Bytes(v)...)
r.buffer.Write(gconv.Bytes(v))
default:
// 否则一律按照可显示的字符串进行转换
r.buffer = append(r.buffer, gconv.String(v)...)
r.buffer.WriteString(gconv.String(v))
}
}
}
@ -130,7 +132,7 @@ func (r *Response) SetAllowCrossDomainRequest(allowOrigin string, allowMethods s
// 返回HTTP Code状态码
func (r *Response) WriteStatus(status int, content...string) {
if len(r.buffer) == 0 {
if r.buffer.Len() == 0 {
// 状态码注册回调函数处理
if status != http.StatusOK {
if f := r.request.Server.getStatusHandler(status, r.request); f != nil {
@ -181,22 +183,23 @@ func (r *Response) RedirectBack() {
// 获取当前缓冲区中的数据
func (r *Response) Buffer() []byte {
return r.buffer
return r.buffer.Bytes()
}
// 获取当前缓冲区中的数据大小
func (r *Response) BufferLength() int {
return len(r.buffer)
return r.buffer.Len()
}
// 手动设置缓冲区内容
func (r *Response) SetBuffer(buffer []byte) {
r.buffer = buffer
func (r *Response) SetBuffer(data []byte) {
r.buffer.Reset()
r.buffer.Write(data)
}
// 清空缓冲区内容
func (r *Response) ClearBuffer() {
r.buffer = r.buffer[:0]
r.buffer.Reset()
}
// 输出缓冲区数据到客户端

View File

@ -8,6 +8,7 @@
package ghttp
import (
"bytes"
"net/http"
)
@ -15,13 +16,13 @@ import (
type ResponseWriter struct {
http.ResponseWriter
Status int // http status
buffer []byte // 缓冲区内容
buffer *bytes.Buffer // 缓冲区内容
}
// 覆盖父级的WriteHeader方法
func (w *ResponseWriter) Write(buffer []byte) (int, error) {
w.buffer = append(w.buffer, buffer...)
return len(buffer), nil
func (w *ResponseWriter) Write(data []byte) (int, error) {
w.buffer.Write(data)
return len(data), nil
}
// 覆盖父级的WriteHeader方法
@ -32,8 +33,8 @@ func (w *ResponseWriter) WriteHeader(code int) {
// 输出buffer数据到客户端
func (w *ResponseWriter) OutputBuffer() {
if len(w.buffer) > 0 {
w.ResponseWriter.Write(w.buffer)
w.buffer = w.buffer[:0]
if w.buffer.Len() > 0 {
w.ResponseWriter.Write(w.buffer.Bytes())
w.buffer.Reset()
}
}

View File

@ -218,16 +218,20 @@ func (s *Server) Start() error {
glog.Debug("ghttp.SetServerRoot:", rp)
}
}
s.AddSearchPath(gfile.SelfDir())
// 添加当前可执行文件运行目录到搜索目录
s.paths.Add(gfile.SelfDir())
// (开发环境)添加main源码包到搜索目录
if p := gfile.MainPkgPath(); p != "" && gfile.Exists(p) {
s.paths.Add(p)
}
// (安全控制)不能访问当前执行文件
s.paths.Remove(gfile.SelfPath())
// 底层http server配置
if s.config.Handler == nil {
s.config.Handler = http.HandlerFunc(s.defaultHttpHandle)
}
// 不允许访问的路由注册
// 不允许访问的路由注册(通过HOOK实现)
if s.config.DenyRoutes != nil {
for _, v := range s.config.DenyRoutes {
s.BindHookHandler(v, HOOK_BEFORE_SERVE, func(r *Request) {
@ -238,12 +242,12 @@ func (s *Server) Start() error {
}
// 配置相关相对路径处理
if !gfile.Exists(s.config.HTTPSCertPath) {
if s.config.HTTPSCertPath != "" && !gfile.Exists(s.config.HTTPSCertPath) {
if t, _ := s.paths.Search(s.config.HTTPSCertPath); t != "" {
s.config.HTTPSCertPath = t
}
}
if !gfile.Exists(s.config.HTTPSKeyPath) {
if s.config.HTTPSKeyPath != "" && !gfile.Exists(s.config.HTTPSKeyPath) {
if t, _ := s.paths.Search(s.config.HTTPSKeyPath); t != "" {
s.config.HTTPSKeyPath = t
}

View File

@ -10,10 +10,8 @@ package ghttp
import (
"fmt"
"gitee.com/johng/gf/g/encoding/ghtml"
"gitee.com/johng/gf/g/os/gfile"
"gitee.com/johng/gf/g/os/gtime"
"net/http"
"net/url"
"os"
"reflect"
"sort"
@ -83,7 +81,7 @@ func (s *Server)handleRequest(w http.ResponseWriter, r *http.Request) {
// 执行静态文件服务/回调控制器/执行对象/方法
if !request.IsExited() {
// 需要再次判断文件是否真实存在,因为文件检索可能使用了缓存,从健壮性考虑这里需要二次判断
if request.IsFileRequest() && !isStaticDir /* && gfile.Exists(staticFile) */ && gfile.SelfPath() != staticFile {
if request.IsFileRequest() && !isStaticDir /* && gfile.Exists(staticFile) */{
// 静态文件
s.serveFile(request, staticFile)
} else {
@ -167,24 +165,20 @@ func (s *Server)serveFile(r *Request, path string) {
}
}
// 目录列表
// 显示目录列表
func (s *Server)listDir(r *Request, f http.File) {
dirs, err := f.Readdir(-1)
files, err := f.Readdir(-1)
if err != nil {
r.Response.WriteStatus(http.StatusInternalServerError, "Error reading directory")
return
}
sort.Slice(dirs, func(i, j int) bool { return dirs[i].Name() < dirs[j].Name() })
sort.Slice(files, func(i, j int) bool { return files[i].Name() < files[j].Name() })
r.Response.Header().Set("Content-Type", "text/html; charset=utf-8")
r.Response.Write("<pre>\n")
for _, d := range dirs {
name := d.Name()
if d.IsDir() {
name += "/"
}
u := url.URL{Path: name}
r.Response.Write(fmt.Sprintf("<a href=\"%s\">%s</a>\n", u.String(), ghtml.SpecialChars(name)))
for _, file := range files {
name := file.Name()
r.Response.Write(fmt.Sprintf("<a href=\"%s/%s\">%s</a>\n", r.URL.Path, name, ghtml.SpecialChars(name)))
}
r.Response.Write("</pre>\n")
}

View File

@ -125,6 +125,21 @@ func (sp *SPath) Search(name string, indexFiles...string) (path string, isDir bo
return "", false
}
// 从搜索路径中移除指定的文件,这样该文件无法给搜索。
// path可以是绝对路径也可以相对路径。
func (sp *SPath) Remove(path string) {
if gfile.Exists(path) {
for _, v := range sp.paths.Slice() {
name := gstr.Replace(path, v, "")
name = sp.formatCacheName(name)
sp.cache.Remove(name)
}
} else {
name := sp.formatCacheName(path)
sp.cache.Remove(name)
}
}
// 返回当前对象缓存的所有路径列表
func (sp *SPath) AllPaths() []string {
paths := sp.cache.Keys()

View File

@ -7,6 +7,7 @@ import (
func main() {
s := g.Server()
s.SetIndexFolder(true)
s.BindHandler("/", func(r *ghttp.Request){
r.Response.Writeln("哈喽世界!")
})

View File

@ -6,5 +6,5 @@ import (
)
func main() {
fmt.Println(gfile.TempDir())
fmt.Println(gfile.SelfPath())
}