mirror of
https://gitee.com/johng/gf
synced 2026-06-07 02:12:11 +08:00
WebServer性能细节改进
This commit is contained in:
@ -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()
|
||||
}
|
||||
|
||||
// 输出缓冲区数据到客户端
|
||||
|
||||
@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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")
|
||||
}
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -7,6 +7,7 @@ import (
|
||||
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.SetIndexFolder(true)
|
||||
s.BindHandler("/", func(r *ghttp.Request){
|
||||
r.Response.Writeln("哈喽世界!")
|
||||
})
|
||||
|
||||
@ -6,5 +6,5 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(gfile.TempDir())
|
||||
fmt.Println(gfile.SelfPath())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user