Sfoglia il codice sorgente

重构服务器代码并移动相关文件

将 `abort`、`cors` 和 `api` 相关功能从 `server` 包移动到 `core` 包,并对 `context`、`request` 和 `writer` 进行了相应的调整和重命名。删除了不再需要的 `server.go` 和 `abort.go` 文件,新增了 `main.go` 作为新的入口点。
SongZihuan 3 mesi fa
parent
commit
b6e0160c41

+ 4 - 2
src/mainfunc/v1.go

@@ -8,6 +8,8 @@ import (
 	"github.com/SongZihuan/huan-proxy/src/flagparser"
 	"github.com/SongZihuan/huan-proxy/src/logger"
 	"github.com/SongZihuan/huan-proxy/src/server"
+	"github.com/SongZihuan/huan-proxy/src/server/httpserver"
+	"github.com/SongZihuan/huan-proxy/src/server/httpsserver"
 	"github.com/SongZihuan/huan-proxy/src/utils"
 	"os"
 )
@@ -78,7 +80,7 @@ func MainV1() int {
 	case <-config.GetSignalChan():
 		return 0
 	case err := <-httpchan:
-		if errors.Is(err, server.ServerStop) {
+		if errors.Is(err, httpserver.ServerStop) {
 			return 0
 		} else if err != nil {
 			return utils.ExitByError(err)
@@ -86,7 +88,7 @@ func MainV1() int {
 			return 0
 		}
 	case err := <-httpschan:
-		if errors.Is(err, server.ServerStop) {
+		if errors.Is(err, httpsserver.ServerStop) {
 			return 0
 		} else if err != nil {
 			return utils.ExitByError(err)

+ 0 - 46
src/server/abort.go

@@ -1,46 +0,0 @@
-package server
-
-import "net/http"
-
-func (s *HuanProxyServer) abort(ctx *Context, code int) {
-	if ctx.Abort {
-		return
-	}
-
-	ctx.Abort = true
-	w, ok := ctx.Writer.(*ResponseWriter)
-	if !ok {
-		return
-	}
-
-	err := w.Reset()
-	if err != nil {
-		ctx.Writer.WriteHeader(http.StatusInternalServerError)
-	} else {
-		ctx.Writer.WriteHeader(code)
-	}
-}
-
-func (s *HuanProxyServer) abortForbidden(ctx *Context) {
-	s.abort(ctx, http.StatusForbidden)
-}
-
-func (s *HuanProxyServer) abortNotFound(ctx *Context) {
-	s.abort(ctx, http.StatusNotFound)
-}
-
-func (s *HuanProxyServer) abortNotAcceptable(ctx *Context) {
-	s.abort(ctx, http.StatusNotAcceptable)
-}
-
-func (s *HuanProxyServer) abortMethodNotAllowed(ctx *Context) {
-	s.abort(ctx, http.StatusMethodNotAllowed)
-}
-
-func (s *HuanProxyServer) abortServerError(ctx *Context) {
-	s.abort(ctx, http.StatusInternalServerError)
-}
-
-func (s *HuanProxyServer) abortNoContent(ctx *Context) {
-	s.abort(ctx, http.StatusNoContent)
-}

+ 33 - 20
src/server/context.go → src/server/context/context.go

@@ -1,28 +1,35 @@
-package server
+package context
 
 import (
 	"fmt"
 	"github.com/SongZihuan/huan-proxy/src/config/rulescompile"
+	"github.com/SongZihuan/huan-proxy/src/server/request/proxyrequest"
+	"github.com/SongZihuan/huan-proxy/src/server/request/readonlyrequest"
+	"github.com/SongZihuan/huan-proxy/src/server/responsewriter"
 	"net/http"
 )
 
 type Context struct {
 	Abort        bool
-	Writer       http.ResponseWriter
-	Request      *ReadOnlyRequest
-	ProxyRequest *ProxyRequest
+	resp         http.ResponseWriter
+	req          *http.Request
+	Writer       *responsewriter.ResponseWriter
+	Request      *readonlyrequest.ReadOnlyRequest
+	ProxyRequest *proxyrequest.ProxyRequest
 	Rule         *rulescompile.RuleCompileConfig
 }
 
 func NewContext(rule *rulescompile.RuleCompileConfig, w http.ResponseWriter, r *http.Request) *Context {
-	var proxyRequest *ProxyRequest = nil
+	var proxyRequest *proxyrequest.ProxyRequest = nil
 	if rule.Type == rulescompile.ProxyTypeAPI {
-		proxyRequest = NewRequest(r)
+		proxyRequest = proxyrequest.NewRequest(r)
 	}
 
 	return &Context{
-		Writer:       NewResponseWriter(w),
-		Request:      NewReadOnlyRequest(r),
+		resp:         w,
+		req:          r,
+		Writer:       responsewriter.NewResponseWriter(w),
+		Request:      readonlyrequest.NewReadOnlyRequest(r),
 		ProxyRequest: proxyRequest,
 		Rule:         rule,
 	}
@@ -42,11 +49,7 @@ func (ctx *Context) ProxyWriteToHttpRRequest() (*http.Request, error) {
 }
 
 func (ctx *Context) WriteToResponse() error {
-	w, ok := ctx.Writer.(*ResponseWriter)
-	if !ok {
-		return nil
-	}
-	err := w.WriteToResponse()
+	err := ctx.Writer.WriteToResponse()
 	if err != nil {
 		return err
 	}
@@ -54,17 +57,15 @@ func (ctx *Context) WriteToResponse() error {
 }
 
 func (ctx *Context) MustWriteToResponse() {
-	if w, ok := ctx.Writer.(*ResponseWriter); ok {
-		w.MustWriteToResponse()
-	}
+	fmt.Printf("Context call must write.\n")
+	ctx.Writer.MustWriteToResponse()
+	fmt.Printf("Context call must write finished.\n")
 }
 
 func (ctx *Context) Reset() error {
 	ctx.Abort = false
 
-	if w, ok := ctx.Writer.(*ResponseWriter); ok {
-		_ = w.Reset()
-	}
+	_ = ctx.Writer.Reset()
 
 	if ctx.ProxyRequest != nil {
 		_ = ctx.ProxyRequest.Reset()
@@ -73,6 +74,18 @@ func (ctx *Context) Reset() error {
 	return nil
 }
 
+func (ctx *Context) StatusOK() {
+	if ctx.Abort {
+		return
+	}
+
+	ctx.Writer.WriteHeader(http.StatusOK)
+}
+
 func (ctx *Context) Redirect(target string, code int) {
-	http.Redirect(ctx.Writer, ctx.Request.req, target, code)
+	if ctx.Abort {
+		return
+	}
+
+	http.Redirect(ctx.Writer, ctx.req, target, code)
 }

+ 44 - 0
src/server/core/abort.go

@@ -0,0 +1,44 @@
+package core
+
+import (
+	"github.com/SongZihuan/huan-proxy/src/server/context"
+	"net/http"
+)
+
+func (c *CoreServer) abort(ctx *context.Context, code int) {
+	if ctx.Abort {
+		return
+	}
+
+	ctx.Abort = true
+	err := ctx.Writer.Reset()
+	if err != nil {
+		ctx.Writer.WriteHeader(http.StatusInternalServerError)
+	} else {
+		ctx.Writer.WriteHeader(code)
+	}
+}
+
+func (c *CoreServer) abortForbidden(ctx *context.Context) {
+	c.abort(ctx, http.StatusForbidden)
+}
+
+func (c *CoreServer) abortNotFound(ctx *context.Context) {
+	c.abort(ctx, http.StatusNotFound)
+}
+
+func (c *CoreServer) abortNotAcceptable(ctx *context.Context) {
+	c.abort(ctx, http.StatusNotAcceptable)
+}
+
+func (c *CoreServer) abortMethodNotAllowed(ctx *context.Context) {
+	c.abort(ctx, http.StatusMethodNotAllowed)
+}
+
+func (c *CoreServer) abortServerError(ctx *context.Context) {
+	c.abort(ctx, http.StatusInternalServerError)
+}
+
+func (c *CoreServer) abortNoContent(ctx *context.Context) {
+	c.abort(ctx, http.StatusNoContent)
+}

+ 15 - 13
src/server/api.go → src/server/core/api.go

@@ -1,17 +1,19 @@
-package server
+package core
 
 import (
 	"fmt"
 	"github.com/SongZihuan/huan-proxy/src/config/rulescompile/actioncompile/rewritecompile"
+	"github.com/SongZihuan/huan-proxy/src/server/context"
+	"github.com/SongZihuan/huan-proxy/src/server/request/readonlyrequest"
 	"github.com/SongZihuan/huan-proxy/src/utils"
 	"net"
 	"strings"
 )
 
-func (s *HuanProxyServer) apiServer(ctx *Context) {
+func (c *CoreServer) apiServer(ctx *context.Context) {
 	proxy := ctx.Rule.Api.Server
 	if proxy == nil {
-		s.abortServerError(ctx)
+		c.abortServerError(ctx)
 		return
 	}
 
@@ -19,9 +21,9 @@ func (s *HuanProxyServer) apiServer(ctx *Context) {
 	ctx.ProxyRequest.URL.Scheme = targetURL.Scheme
 	ctx.ProxyRequest.URL.Host = targetURL.Host
 
-	s.processProxyHeader(ctx)
+	c.processProxyHeader(ctx)
 
-	ctx.ProxyRequest.URL.Path = s.apiRewrite(utils.ProcessURLPath(ctx.ProxyRequest.URL.Path), ctx.Rule.Api.AddPath, ctx.Rule.Api.SubPath, ctx.Rule.Api.Rewrite)
+	ctx.ProxyRequest.URL.Path = c.apiRewrite(utils.ProcessURLPath(ctx.ProxyRequest.URL.Path), ctx.Rule.Api.AddPath, ctx.Rule.Api.SubPath, ctx.Rule.Api.Rewrite)
 
 	for _, h := range ctx.Rule.Api.HeaderSet {
 		ctx.ProxyRequest.Header.Set(h.Header, h.Value)
@@ -51,18 +53,18 @@ func (s *HuanProxyServer) apiServer(ctx *Context) {
 
 	ctx.ProxyRequest.URL.RawQuery = query.Encode()
 
-	s.writeViaHeader(ctx)
+	c.writeViaHeader(ctx)
 
 	req, err := ctx.ProxyWriteToHttpRRequest()
 	if err != nil {
-		s.abortServerError(ctx)
+		c.abortServerError(ctx)
 		return
 	}
 
 	proxy.ServeHTTP(ctx.Writer, req) // 反向代理
 }
 
-func (s *HuanProxyServer) apiRewrite(srcpath string, prefix string, suffix string, rewrite *rewritecompile.RewriteCompileConfig) string {
+func (c *CoreServer) apiRewrite(srcpath string, prefix string, suffix string, rewrite *rewritecompile.RewriteCompileConfig) string {
 	srcpath = utils.ProcessURLPath(srcpath)
 	prefix = utils.ProcessURLPath(prefix)
 	suffix = utils.ProcessURLPath(suffix)
@@ -80,7 +82,7 @@ func (s *HuanProxyServer) apiRewrite(srcpath string, prefix string, suffix strin
 	return srcpath
 }
 
-func (s *HuanProxyServer) processProxyHeader(ctx *Context) {
+func (c *CoreServer) processProxyHeader(ctx *context.Context) {
 	if ctx.Request.RemoteAddr() == "" {
 		return
 	}
@@ -96,9 +98,9 @@ func (s *HuanProxyServer) processProxyHeader(ctx *Context) {
 	var host, proto string
 
 	if ctx.Request.Header().Get("Forwarded") != "" {
-		ProxyList, ForwardedList, host, proto = s.getProxyListForwarder(remoteIP, ctx.Request)
+		ProxyList, ForwardedList, host, proto = c.getProxyListForwarder(remoteIP, ctx.Request)
 	} else if ctx.Request.Header().Get("X-Forwarded-For") != "" {
-		ProxyList, ForwardedList, host, proto = s.getProxyListFromXForwardedFor(remoteIP, ctx.Request)
+		ProxyList, ForwardedList, host, proto = c.getProxyListFromXForwardedFor(remoteIP, ctx.Request)
 	} else {
 		host = ctx.Request.Header().Get("X-Forwarded-Host")
 		proto = ctx.Request.Header().Get("X-Forwarded-Proto")
@@ -130,7 +132,7 @@ func (s *HuanProxyServer) processProxyHeader(ctx *Context) {
 	ctx.ProxyRequest.Header.Set("X-Forwarded-Proto", proto)
 }
 
-func (s *HuanProxyServer) getProxyListForwarder(remoteIP net.IP, r *ReadOnlyRequest) ([]string, []string, string, string) {
+func (c *CoreServer) getProxyListForwarder(remoteIP net.IP, r *readonlyrequest.ReadOnlyRequest) ([]string, []string, string, string) {
 	ForwardedList := strings.Split(r.Header().Get("Forwarded"), ",")
 	ProxyList := make([]string, 0, len(ForwardedList)+1)
 	NewForwardedList := make([]string, 0, len(ForwardedList)+1)
@@ -174,7 +176,7 @@ func (s *HuanProxyServer) getProxyListForwarder(remoteIP net.IP, r *ReadOnlyRequ
 	return ProxyList, NewForwardedList, host, proto
 }
 
-func (s *HuanProxyServer) getProxyListFromXForwardedFor(remoteIP net.IP, r *ReadOnlyRequest) ([]string, []string, string, string) {
+func (c *CoreServer) getProxyListFromXForwardedFor(remoteIP net.IP, r *readonlyrequest.ReadOnlyRequest) ([]string, []string, string, string) {
 	XFroWardedForList := strings.Split(r.Header().Get("X-Forwarded-For"), ",")
 	ProxyList := make([]string, 0, len(XFroWardedForList)+1)
 	NewForwardedList := make([]string, 0, len(XFroWardedForList)+1)

+ 1 - 0
src/server/core/core.go

@@ -0,0 +1 @@
+package core

+ 6 - 5
src/server/cors.go → src/server/core/cors.go

@@ -1,15 +1,16 @@
-package server
+package core
 
 import (
 	"fmt"
 	"github.com/SongZihuan/huan-proxy/src/config/rulescompile/actioncompile/corscompile"
+	"github.com/SongZihuan/huan-proxy/src/server/context"
 	"net/http"
 )
 
-func (s *HuanProxyServer) cors(corsRule *corscompile.CorsCompileConfig, ctx *Context) bool {
+func (c *CoreServer) cors(corsRule *corscompile.CorsCompileConfig, ctx *context.Context) bool {
 	if corsRule.Ignore {
 		if ctx.Request.Method() == http.MethodOptions {
-			s.abortMethodNotAllowed(ctx)
+			c.abortMethodNotAllowed(ctx)
 			return false
 		} else {
 			return true
@@ -18,12 +19,12 @@ func (s *HuanProxyServer) cors(corsRule *corscompile.CorsCompileConfig, ctx *Con
 
 	origin := ctx.Request.Header().Get("Origin")
 	if origin == "" {
-		s.abortForbidden(ctx)
+		c.abortForbidden(ctx)
 		return false
 	}
 
 	if !corsRule.InOriginList(origin) {
-		s.abortForbidden(ctx)
+		c.abortForbidden(ctx)
 		return false
 	}
 

+ 7 - 0
src/server/core/default.go

@@ -0,0 +1,7 @@
+package core
+
+import "net/http"
+
+func (c *CoreServer) defaultResponse(w http.ResponseWriter) {
+	w.WriteHeader(http.StatusNotFound)
+}

+ 23 - 22
src/server/dir.go → src/server/core/dir.go

@@ -1,9 +1,10 @@
-package server
+package core
 
 import (
 	"github.com/SongZihuan/huan-proxy/src/config/rulescompile"
 	"github.com/SongZihuan/huan-proxy/src/config/rulescompile/actioncompile/rewritecompile"
 	"github.com/SongZihuan/huan-proxy/src/config/rulescompile/matchcompile"
+	"github.com/SongZihuan/huan-proxy/src/server/context"
 	"github.com/SongZihuan/huan-proxy/src/utils"
 	"github.com/gabriel-vasile/mimetype"
 	"net/http"
@@ -15,13 +16,13 @@ import (
 const IndexMaxDeep = 5
 const DefaultIgnoreFileMap = 20
 
-func (s *HuanProxyServer) dirServer(ctx *Context) {
-	if !s.cors(ctx.Rule.Dir.Cors, ctx) {
+func (c *CoreServer) dirServer(ctx *context.Context) {
+	if !c.cors(ctx.Rule.Dir.Cors, ctx) {
 		return
 	}
 
 	if ctx.Request.Method() != http.MethodGet {
-		s.abortMethodNotAllowed(ctx)
+		c.abortMethodNotAllowed(ctx)
 		return
 	}
 
@@ -31,23 +32,23 @@ func (s *HuanProxyServer) dirServer(ctx *Context) {
 
 	url := utils.ProcessURLPath(ctx.Request.URL().Path)
 	if ctx.Rule.MatchType == matchcompile.RegexMatch {
-		fileAccess = s.dirRewrite("", ctx.Rule.Dir.AddPath, ctx.Rule.Dir.SubPath, ctx.Rule.Dir.Rewrite)
+		fileAccess = c.dirRewrite("", ctx.Rule.Dir.AddPath, ctx.Rule.Dir.SubPath, ctx.Rule.Dir.Rewrite)
 		filePath = path.Join(dirBasePath, fileAccess)
 	} else {
 		if url == ctx.Rule.MatchPath {
-			fileAccess = s.dirRewrite("", ctx.Rule.Dir.AddPath, ctx.Rule.Dir.SubPath, ctx.Rule.Dir.Rewrite)
+			fileAccess = c.dirRewrite("", ctx.Rule.Dir.AddPath, ctx.Rule.Dir.SubPath, ctx.Rule.Dir.Rewrite)
 			filePath = path.Join(dirBasePath, fileAccess)
 		} else if strings.HasPrefix(url, ctx.Rule.MatchPath+"/") {
-			fileAccess = s.dirRewrite(url[len(ctx.Rule.MatchPath+"/"):], ctx.Rule.Dir.AddPath, ctx.Rule.Dir.SubPath, ctx.Rule.Dir.Rewrite)
+			fileAccess = c.dirRewrite(url[len(ctx.Rule.MatchPath+"/"):], ctx.Rule.Dir.AddPath, ctx.Rule.Dir.SubPath, ctx.Rule.Dir.Rewrite)
 			filePath = path.Join(dirBasePath, fileAccess)
 		} else {
-			s.abortNotFound(ctx)
+			c.abortNotFound(ctx)
 			return
 		}
 	}
 
 	if filePath == "" {
-		s.abortNotFound(ctx) // 正常清空不会走到这个流程
+		c.abortNotFound(ctx) // 正常清空不会走到这个流程
 		return
 	}
 
@@ -55,46 +56,46 @@ func (s *HuanProxyServer) dirServer(ctx *Context) {
 		// 判断这个文件是否被ignore,因为ignore是从dirBasePath写起,也可以是完整路径,因此filePath和fileAccess都要判断
 		for _, ignore := range ctx.Rule.Dir.IgnoreFile {
 			if ignore.CheckName(fileAccess) || ignore.CheckName(filePath) {
-				s.abortNotFound(ctx)
+				c.abortNotFound(ctx)
 				return
 			}
 		}
 	} else {
-		filePath = s.getIndexFile(ctx.Rule, filePath)
+		filePath = c.getIndexFile(ctx.Rule, filePath)
 		if filePath == "" || !utils.IsFile(filePath) {
-			s.abortNotFound(ctx)
+			c.abortNotFound(ctx)
 			return
 		}
 	}
 
 	if !utils.CheckIfSubPath(dirBasePath, filePath) {
-		s.abortForbidden(ctx)
+		c.abortForbidden(ctx)
 		return
 	}
 
 	file, err := os.ReadFile(filePath)
 	if err != nil {
-		s.abortNotFound(ctx)
+		c.abortNotFound(ctx)
 		return
 	}
 
 	mimeType := mimetype.Detect(file)
 	accept := ctx.Request.Header().Get("Accept")
 	if !utils.AcceptMimeType(accept, mimeType.String()) {
-		s.abortNotAcceptable(ctx)
+		c.abortNotAcceptable(ctx)
 		return
 	}
 
 	_, err = ctx.Writer.Write(file)
 	if err != nil {
-		s.abortServerError(ctx)
+		c.abortServerError(ctx)
 		return
 	}
 	ctx.Writer.Header().Set("Content-Type", mimeType.String())
-	s.statusOK(ctx)
+	c.statusOK(ctx)
 }
 
-func (s *HuanProxyServer) dirRewrite(srcpath string, prefix string, suffix string, rewrite *rewritecompile.RewriteCompileConfig) string {
+func (c *CoreServer) dirRewrite(srcpath string, prefix string, suffix string, rewrite *rewritecompile.RewriteCompileConfig) string {
 	if strings.HasPrefix(srcpath, suffix) {
 		srcpath = srcpath[len(suffix):]
 	}
@@ -108,11 +109,11 @@ func (s *HuanProxyServer) dirRewrite(srcpath string, prefix string, suffix strin
 	return srcpath
 }
 
-func (s *HuanProxyServer) getIndexFile(rule *rulescompile.RuleCompileConfig, dir string) string {
-	return s._getIndexFile(rule, dir, "", IndexMaxDeep)
+func (c *CoreServer) getIndexFile(rule *rulescompile.RuleCompileConfig, dir string) string {
+	return c._getIndexFile(rule, dir, "", IndexMaxDeep)
 }
 
-func (s *HuanProxyServer) _getIndexFile(rule *rulescompile.RuleCompileConfig, baseDir string, nextDir string, deep int) string {
+func (c *CoreServer) _getIndexFile(rule *rulescompile.RuleCompileConfig, baseDir string, nextDir string, deep int) string {
 	if deep == 0 {
 		return ""
 	}
@@ -170,7 +171,7 @@ func (s *HuanProxyServer) _getIndexFile(rule *rulescompile.RuleCompileConfig, ba
 	if indexFile != nil {
 		return path.Join(dir, indexFile.Name())
 	} else if indexDir != nil {
-		return s._getIndexFile(rule, dir, indexDir.Name(), deep-1)
+		return c._getIndexFile(rule, dir, indexDir.Name(), deep-1)
 	} else {
 		return ""
 	}

+ 9 - 8
src/server/file.go → src/server/core/file.go

@@ -1,40 +1,41 @@
-package server
+package core
 
 import (
+	"github.com/SongZihuan/huan-proxy/src/server/context"
 	"github.com/SongZihuan/huan-proxy/src/utils"
 	"github.com/gabriel-vasile/mimetype"
 	"net/http"
 	"os"
 )
 
-func (s *HuanProxyServer) fileServer(ctx *Context) {
-	if !s.cors(ctx.Rule.File.Cors, ctx) {
+func (c *CoreServer) fileServer(ctx *context.Context) {
+	if !c.cors(ctx.Rule.File.Cors, ctx) {
 		return
 	}
 
 	if ctx.Request.Method() != http.MethodGet {
-		s.abortMethodNotAllowed(ctx)
+		c.abortMethodNotAllowed(ctx)
 		return
 	}
 
 	file, err := os.ReadFile(ctx.Rule.File.Path)
 	if err != nil {
-		s.abortServerError(ctx)
+		c.abortServerError(ctx)
 		return
 	}
 
 	mimeType := mimetype.Detect(file)
 	accept := ctx.Request.Header().Get("Accept")
 	if !utils.AcceptMimeType(accept, mimeType.String()) {
-		s.abortNotAcceptable(ctx)
+		c.abortNotAcceptable(ctx)
 		return
 	}
 
 	_, err = ctx.Writer.Write(file)
 	if err != nil {
-		s.abortServerError(ctx)
+		c.abortServerError(ctx)
 		return
 	}
 	ctx.Writer.Header().Set("Content-Type", mimeType.String())
-	s.statusOK(ctx)
+	c.statusOK(ctx)
 }

+ 7 - 7
src/server/hptag.go → src/server/core/hptag.go

@@ -1,18 +1,18 @@
-package server
+package core
 
 import (
 	"fmt"
 	resource "github.com/SongZihuan/huan-proxy"
 	"github.com/SongZihuan/huan-proxy/src/config/rulescompile/actioncompile/apicompile"
+	"github.com/SongZihuan/huan-proxy/src/server/context"
 	"github.com/SongZihuan/huan-proxy/src/utils"
-	"net/http"
 	"strings"
 )
 
 const XHuanProxyHeaer = apicompile.XHuanProxyHeaer
 const ViaHeader = apicompile.ViaHeader
 
-func (s *HuanProxyServer) writeHuanProxyHeader(ctx *Context) {
+func (c *CoreServer) writeHuanProxyHeader(ctx *context.Context) {
 	version := strings.TrimSpace(utils.StringToOnlyPrint(resource.Version))
 	ctx.Writer.Header().Set(XHuanProxyHeaer, version)
 	if ctx.ProxyRequest != nil {
@@ -20,7 +20,7 @@ func (s *HuanProxyServer) writeHuanProxyHeader(ctx *Context) {
 	}
 }
 
-func (s *HuanProxyServer) writeViaHeader(ctx *Context) {
+func (c *CoreServer) writeViaHeader(ctx *context.Context) {
 	info := fmt.Sprintf("%s %s", ctx.Request.MustProto(), ctx.Rule.Api.Via)
 
 	reqHeader := ctx.Request.Header().Get(ViaHeader)
@@ -40,10 +40,10 @@ func (s *HuanProxyServer) writeViaHeader(ctx *Context) {
 	ctx.Writer.Header().Set(ViaHeader, respHeader)
 }
 
-func (s *HuanProxyServer) statusOK(ctx *Context) {
-	ctx.Writer.WriteHeader(http.StatusOK)
+func (c *CoreServer) statusOK(ctx *context.Context) {
+	ctx.StatusOK()
 }
 
-func (s *HuanProxyServer) statusRedirect(ctx *Context, url string, code int) {
+func (c *CoreServer) statusRedirect(ctx *context.Context, url string, code int) {
 	ctx.Redirect(url, code)
 }

+ 2 - 2
src/server/match.go → src/server/core/match.go

@@ -1,4 +1,4 @@
-package server
+package core
 
 import (
 	"github.com/SongZihuan/huan-proxy/src/config/rulescompile"
@@ -8,7 +8,7 @@ import (
 	"strings"
 )
 
-func (s *HuanProxyServer) matchURL(rule *rulescompile.RuleCompileConfig, r *http.Request) bool {
+func (c *CoreServer) matchURL(rule *rulescompile.RuleCompileConfig, r *http.Request) bool {
 	url := utils.ProcessURLPath(r.URL.Path)
 	if rule.MatchType == matchcompile.RegexMatch {
 		if rule.MatchRegex.MatchString(url) || rule.MatchRegex.MatchString(url+"/") {

+ 55 - 0
src/server/core/normalserver.go

@@ -0,0 +1,55 @@
+package core
+
+import (
+	"fmt"
+	"github.com/SongZihuan/huan-proxy/src/config"
+	"github.com/SongZihuan/huan-proxy/src/config/rulescompile"
+	"github.com/SongZihuan/huan-proxy/src/server/context"
+	"net/http"
+)
+
+func (c *CoreServer) CoreServeHTTP(writer http.ResponseWriter, r *http.Request) {
+	func() {
+	RuleCycle:
+		for _, rule := range c.GetRulesList() {
+			if !c.matchURL(rule, r) {
+				continue RuleCycle
+			}
+
+			ctx := context.NewContext(rule, writer, r)
+
+			if !c.checkProxyTrust(ctx) {
+				return
+			}
+
+			c.writeHuanProxyHeader(ctx)
+
+			if rule.Type == rulescompile.ProxyTypeFile {
+				c.fileServer(ctx)
+			} else if rule.Type == rulescompile.ProxyTypeDir {
+				c.dirServer(ctx)
+			} else if rule.Type == rulescompile.ProxyTypeAPI {
+				c.apiServer(ctx)
+			} else if rule.Type == rulescompile.ProxyTypeRedirect {
+				c.redirectServer(ctx)
+			} else {
+				c.abortServerError(ctx)
+			}
+
+			fmt.Printf("ctx.Abort: %v\n", ctx.Abort)
+			fmt.Printf("config.GetConfig().NotAbort.IsEnable(false) = %v\n", config.GetConfig().NotAbort.IsEnable(false))
+			if ctx.Abort && config.GetConfig().NotAbort.IsEnable(false) {
+				_ = ctx.Reset()
+				continue RuleCycle
+			}
+
+			fmt.Printf("TAG A\n")
+			ctx.MustWriteToResponse()
+			return
+
+		}
+
+		c.defaultResponse(writer)
+		// 此处虽然w为Writer,但应该交由LoggerServer来处理写入
+	}()
+}

+ 7 - 6
src/server/proxytrust.go → src/server/core/proxytrust.go

@@ -1,29 +1,30 @@
-package server
+package core
 
 import (
+	"github.com/SongZihuan/huan-proxy/src/server/context"
 	"github.com/SongZihuan/huan-proxy/src/utils"
 	"net"
 )
 
-func (s *HuanProxyServer) checkProxyTrust(ctx *Context) bool {
+func (c *CoreServer) checkProxyTrust(ctx *context.Context) bool {
 	if !ctx.Rule.UseTrustedIPs {
 		return true
 	}
 
 	if ctx.Request.RemoteAddr() == "" {
-		s.abortForbidden(ctx)
+		c.abortForbidden(ctx)
 		return false
 	}
 
 	remoteIPStr, _, err := net.SplitHostPort(ctx.Request.RemoteAddr())
 	if err != nil {
-		s.abortForbidden(ctx)
+		c.abortForbidden(ctx)
 		return false
 	}
 
 	remoteIP := net.ParseIP(remoteIPStr)
 	if remoteIP == nil {
-		s.abortForbidden(ctx)
+		c.abortForbidden(ctx)
 		return false
 	}
 
@@ -45,6 +46,6 @@ func (s *HuanProxyServer) checkProxyTrust(ctx *Context) bool {
 		}
 	}
 
-	s.abortForbidden(ctx)
+	c.abortForbidden(ctx)
 	return false
 }

+ 28 - 0
src/server/core/redirect.go

@@ -0,0 +1,28 @@
+package core
+
+import (
+	"fmt"
+	"github.com/SongZihuan/huan-proxy/src/config/rulescompile/actioncompile/rewritecompile"
+	"github.com/SongZihuan/huan-proxy/src/server/context"
+	"net/url"
+)
+
+func (c *CoreServer) redirectServer(ctx *context.Context) {
+	target := c.redirectRewrite(ctx.Rule.Redirect.Address, ctx.Rule.Redirect.Rewrite)
+
+	if _, err := url.Parse(target); err != nil {
+		c.abortServerError(ctx)
+		return
+	}
+
+	fmt.Printf("target: %s\n", target)
+	c.statusRedirect(ctx, target, ctx.Rule.Redirect.Code)
+}
+
+func (c *CoreServer) redirectRewrite(address string, rewrite *rewritecompile.RewriteCompileConfig) string {
+	if rewrite.Use && rewrite.Regex != nil {
+		rewrite.Regex.ReplaceAllString(address, rewrite.Target)
+	}
+
+	return address
+}

+ 53 - 0
src/server/core/server.go

@@ -0,0 +1,53 @@
+package core
+
+import (
+	"errors"
+	"github.com/SongZihuan/huan-proxy/src/config"
+	"github.com/SongZihuan/huan-proxy/src/config/rulescompile"
+	"github.com/SongZihuan/huan-proxy/src/flagparser"
+	"github.com/SongZihuan/huan-proxy/src/server/responsewriter"
+	"net/http"
+)
+
+type Middleware interface {
+	ServeHTTP(http.ResponseWriter, *http.Request, http.HandlerFunc)
+}
+
+type CoreServer struct {
+	logger Middleware
+}
+
+func NewCoreServer(logger Middleware) *CoreServer {
+	if !flagparser.IsReady() || !config.IsReady() {
+		panic("not ready")
+	}
+	return &CoreServer{
+		logger: logger,
+	}
+}
+
+func (c *CoreServer) GetConfig() *config.YamlConfig {
+	// 不用检查Ready,因为在NewServer的时候已经检查过了
+	return config.GetConfig()
+}
+
+func (c *CoreServer) GetRules() *rulescompile.RuleListCompileConfig {
+	// 不用检查Ready,因为在NewServer的时候已经检查过了
+	return config.GetRules()
+}
+
+func (c *CoreServer) GetRulesList() []*rulescompile.RuleCompileConfig {
+	// 不用检查Ready,因为在NewServer的时候已经检查过了
+	return c.GetRules().Rules
+}
+
+func (c *CoreServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+	writer := responsewriter.NewResponseWriter(w)
+
+	c.logger.ServeHTTP(writer, r, c.CoreServeHTTP)
+
+	err := writer.WriteToResponse()
+	if err != nil && !errors.Is(err, responsewriter.ErrHasWriter) {
+		writer.ServerError()
+	}
+}

+ 0 - 7
src/server/default.go

@@ -1,7 +0,0 @@
-package server
-
-import "net/http"
-
-func (s *HuanProxyServer) defaultResponse(w http.ResponseWriter) {
-	w.WriteHeader(http.StatusNotFound)
-}

+ 55 - 0
src/server/httpserver/server.go

@@ -0,0 +1,55 @@
+package httpserver
+
+import (
+	"errors"
+	"fmt"
+	"github.com/SongZihuan/huan-proxy/src/config"
+	"github.com/SongZihuan/huan-proxy/src/logger"
+	"net/http"
+)
+
+var ServerStop = fmt.Errorf("https server stop")
+
+type HTTPServer struct {
+	cfg     *config.HttpConfig
+	server  *http.Server
+	handler http.Handler
+}
+
+func NewHTTPServer(handler http.Handler) *HTTPServer {
+	httpcfg := config.GetConfig().Http
+
+	if httpcfg.Address == "" {
+		return nil
+	}
+
+	return &HTTPServer{
+		cfg:     &httpcfg,
+		server:  nil,
+		handler: handler,
+	}
+}
+
+func (s *HTTPServer) LoadHttp() error {
+	s.server = &http.Server{
+		Addr:    s.cfg.Address,
+		Handler: s.handler,
+	}
+	return nil
+}
+
+func (s *HTTPServer) RunHttp(_httpschan chan error) chan error {
+	go func(httpschan chan error) {
+		logger.Infof("start http server in %s", s.cfg.Address)
+		err := s.server.ListenAndServe()
+		if err != nil && errors.Is(err, http.ErrServerClosed) {
+			httpschan <- ServerStop
+			return
+		} else if err != nil {
+			httpschan <- err
+			return
+		}
+	}(_httpschan)
+
+	return _httpschan
+}

+ 11 - 115
src/server/server.go → src/server/httpsserver/server.go

@@ -1,4 +1,4 @@
-package server
+package httpsserver
 
 import (
 	"context"
@@ -9,21 +9,13 @@ import (
 	"fmt"
 	"github.com/SongZihuan/huan-proxy/src/certssl"
 	"github.com/SongZihuan/huan-proxy/src/config"
-	"github.com/SongZihuan/huan-proxy/src/config/rulescompile"
-	"github.com/SongZihuan/huan-proxy/src/flagparser"
 	"github.com/SongZihuan/huan-proxy/src/logger"
 	"net/http"
 	"sync"
 	"time"
 )
 
-var ServerStop = fmt.Errorf("server stop")
-
-type HTTPServer struct {
-	cfg     *config.HttpConfig
-	server  *http.Server
-	handler http.Handler
-}
+var ServerStop = fmt.Errorf("https server stop")
 
 type HTTPSServer struct {
 	cfg         *config.HttpsConfig
@@ -35,89 +27,21 @@ type HTTPSServer struct {
 	handler     http.Handler
 }
 
-type LogServer struct {
-	skip   map[string]struct{}
-	isTerm bool
-	writer func(msg string)
-}
-
-type HuanProxyServer struct {
-	http  HTTPServer
-	https HTTPSServer
-	LogServer
-}
-
-func NewHuanProxyServer() *HuanProxyServer {
-	if !flagparser.IsReady() || !config.IsReady() {
-		panic("not ready")
-	}
-
-	skip := make(map[string]struct{}, 10)
-	httpcfg := config.GetConfig().Http
+func NewHTTPSServer(handler http.Handler) *HTTPSServer {
 	httpscfg := config.GetConfig().Https
 
-	res := &HuanProxyServer{
-		http: HTTPServer{
-			cfg:    &httpcfg,
-			server: nil,
-		},
-
-		https: HTTPSServer{
-			cfg:    &httpscfg,
-			server: nil,
-		},
-
-		LogServer: LogServer{
-			skip:   skip,
-			isTerm: logger.IsInfoTermNotDumb(),
-			writer: logger.InfoWrite,
-		},
+	if httpscfg.Address == "" {
+		return nil
 	}
 
-	res.http.handler = res
-	res.https.handler = res
-
-	return res
-}
-
-func (s *HuanProxyServer) GetConfig() *config.YamlConfig {
-	// 不用检查Ready,因为在NewServer的时候已经检查过了
-	return config.GetConfig()
-}
-
-func (s *HuanProxyServer) GetRules() *rulescompile.RuleListCompileConfig {
-	// 不用检查Ready,因为在NewServer的时候已经检查过了
-	return config.GetRules()
-}
-
-func (s *HuanProxyServer) GetRulesList() []*rulescompile.RuleCompileConfig {
-	// 不用检查Ready,因为在NewServer的时候已经检查过了
-	return s.GetRules().Rules
-}
-
-func (s *HuanProxyServer) Run(httpschan chan error, httpchan chan error) (err error) {
-	if s.https.cfg.Address != "" {
-		err := s.https.loadHttps()
-		if err != nil {
-			return err
-		}
-
-		s.https.runHttps(httpschan)
-	}
-
-	if s.http.cfg.Address != "" {
-		err := s.http.loadHttp()
-		if err != nil {
-			return err
-		}
-
-		s.http.runHttp(httpchan)
+	return &HTTPSServer{
+		cfg:     &httpscfg,
+		server:  nil,
+		handler: handler,
 	}
-
-	return nil
 }
 
-func (s *HTTPSServer) loadHttps() error {
+func (s *HTTPSServer) LoadHttps() error {
 	privateKey, certificate, issuerCertificate, err := certssl.GetCertificateAndPrivateKey(s.cfg.SSLCertDir, s.cfg.SSLEmail, s.cfg.AliyunDNSAccessKey, s.cfg.AliyunDNSAccessSecret, s.cfg.SSLDomain)
 	if err != nil {
 		return fmt.Errorf("init htttps cert ssl server error: %s", err.Error())
@@ -164,7 +88,7 @@ func (s *HTTPSServer) reloadHttps() error {
 	return nil
 }
 
-func (s *HTTPSServer) runHttps(_httpschan chan error) chan error {
+func (s *HTTPSServer) RunHttps(_httpschan chan error) chan error {
 	_watchstopchan := make(chan bool)
 
 	s.watchCertificate(_watchstopchan)
@@ -240,31 +164,3 @@ func (s *HTTPSServer) watchCertificate(stopchan chan bool) {
 		}
 	}()
 }
-
-func (s *HTTPServer) loadHttp() error {
-	s.server = &http.Server{
-		Addr:    s.cfg.Address,
-		Handler: s.handler,
-	}
-	return nil
-}
-
-func (s *HTTPServer) runHttp(_httpschan chan error) chan error {
-	go func(httpschan chan error) {
-		logger.Infof("start http server in %s", s.cfg.Address)
-		err := s.server.ListenAndServe()
-		if err != nil && errors.Is(err, http.ErrServerClosed) {
-			httpschan <- ServerStop
-			return
-		} else if err != nil {
-			httpschan <- err
-			return
-		}
-	}(_httpschan)
-
-	return _httpschan
-}
-
-func (s *HuanProxyServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
-	s.LoggerServerHTTP(w, r, s.NormalServeHTTP)
-}

+ 57 - 0
src/server/main.go

@@ -0,0 +1,57 @@
+package server
+
+import (
+	"github.com/SongZihuan/huan-proxy/src/config"
+	"github.com/SongZihuan/huan-proxy/src/flagparser"
+	"github.com/SongZihuan/huan-proxy/src/server/core"
+	"github.com/SongZihuan/huan-proxy/src/server/httpserver"
+	"github.com/SongZihuan/huan-proxy/src/server/httpsserver"
+	"github.com/SongZihuan/huan-proxy/src/server/middleware/loggerserver"
+)
+
+type HuanProxyServer struct {
+	http   *httpserver.HTTPServer
+	https  *httpsserver.HTTPSServer
+	logger *loggerserver.LogServer
+	server *core.CoreServer
+}
+
+func NewHuanProxyServer() *HuanProxyServer {
+	if !flagparser.IsReady() || !config.IsReady() {
+		panic("not ready")
+	}
+
+	logger := loggerserver.NewLogServer()
+	server := core.NewCoreServer(logger)
+
+	res := &HuanProxyServer{
+		logger: loggerserver.NewLogServer(),
+		server: server,
+		http:   httpserver.NewHTTPServer(server),
+		https:  httpsserver.NewHTTPSServer(server),
+	}
+
+	return res
+}
+
+func (s *HuanProxyServer) Run(httpschan chan error, httpchan chan error) (err error) {
+	if s.https != nil {
+		err := s.https.LoadHttps()
+		if err != nil {
+			return err
+		}
+
+		s.https.RunHttps(httpschan)
+	}
+
+	if s.http != nil {
+		err := s.http.LoadHttp()
+		if err != nil {
+			return err
+		}
+
+		s.http.RunHttp(httpchan)
+	}
+
+	return nil
+}

+ 41 - 15
src/server/loggerserver.go → src/server/middleware/loggerserver/loggerserver.go

@@ -2,10 +2,13 @@
 // Use of this source code is governed by a MIT style
 // license that can be found in the LICENSE.gin file.
 
-package server
+package loggerserver
 
 import (
+	"errors"
 	"fmt"
+	"github.com/SongZihuan/huan-proxy/src/logger"
+	"github.com/SongZihuan/huan-proxy/src/server/responsewriter"
 	"io"
 	"net/http"
 	"time"
@@ -22,6 +25,20 @@ const (
 	reset   = "\033[0m"
 )
 
+type LogServer struct {
+	skip      map[string]struct{}
+	isTerm    bool
+	logWriter func(msg string)
+}
+
+func NewLogServer() *LogServer {
+	return &LogServer{
+		skip:      make(map[string]struct{}, 10),
+		isTerm:    logger.IsInfoTermNotDumb(),
+		logWriter: logger.InfoWrite,
+	}
+}
+
 // LoggerConfig defines the config for Logger middleware.
 type LoggerConfig struct {
 	// Optional. Default value is gin.defaultLogFormatter
@@ -110,9 +127,9 @@ func (p *LogFormatterParams) ResetColor() string {
 	return reset
 }
 
-func (s *HuanProxyServer) Formatter(param LogFormatterParams) string {
+func (ls *LogServer) Formatter(param LogFormatterParams) string {
 	var statusColor, methodColor, resetColor string
-	if s.isTerm {
+	if ls.isTerm {
 		statusColor = param.StatusCodeColor()
 		methodColor = param.MethodColor()
 		resetColor = param.ResetColor()
@@ -131,24 +148,28 @@ func (s *HuanProxyServer) Formatter(param LogFormatterParams) string {
 	)
 }
 
-func (s *HuanProxyServer) LoggerServerHTTP(_w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
+func (ls *LogServer) ServeHTTP(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
 	// Start timer
+	serverErr := false // 若为true则为server error(http.StatusInternalServerError)
 	start := time.Now()
 	path := r.URL.Path
 	raw := r.URL.RawQuery
 
-	w, ok := NewResponseWriter(_w).(*ResponseWriter)
-	if !ok {
-		_w.WriteHeader(http.StatusInternalServerError)
-		return
-	}
+	writer := responsewriter.NewResponseWriter(w)
 
 	// Process request
-	next(w, r)
+	next(writer, r)
+
+	err := writer.WriteToResponse()
+	if err != nil && !errors.Is(err, responsewriter.ErrHasWriter) {
+		serverErr = true
+		writer.ServerError()
+		// 请求发生服务器故障,日志服务继续
+	}
 
 	param := LogFormatterParams{
 		Request: r,
-		isTerm:  s.isTerm,
+		isTerm:  ls.isTerm,
 		Keys:    make(map[string]any),
 	}
 
@@ -158,8 +179,13 @@ func (s *HuanProxyServer) LoggerServerHTTP(_w http.ResponseWriter, r *http.Reque
 
 	param.RemoteAddr = r.RemoteAddr
 	param.Method = r.Method
-	param.StatusCode = w.Status()
-	param.BodySize = w.Size()
+	if serverErr {
+		param.StatusCode = http.StatusInternalServerError
+		param.BodySize = 0
+	} else {
+		param.StatusCode = writer.Status()
+		param.BodySize = writer.Size()
+	}
 
 	if raw != "" {
 		path = path + "?" + raw
@@ -167,7 +193,7 @@ func (s *HuanProxyServer) LoggerServerHTTP(_w http.ResponseWriter, r *http.Reque
 
 	param.Path = path
 
-	if s.writer != nil {
-		s.writer(s.Formatter(param))
+	if ls.logWriter != nil {
+		ls.logWriter(ls.Formatter(param))
 	}
 }

+ 0 - 48
src/server/normalserver.go

@@ -1,48 +0,0 @@
-package server
-
-import (
-	"github.com/SongZihuan/huan-proxy/src/config"
-	"github.com/SongZihuan/huan-proxy/src/config/rulescompile"
-	"net/http"
-)
-
-func (s *HuanProxyServer) NormalServeHTTP(w http.ResponseWriter, r *http.Request) {
-	func() {
-	RuleCycle:
-		for _, rule := range s.GetRulesList() {
-			if !s.matchURL(rule, r) {
-				continue RuleCycle
-			}
-
-			ctx := NewContext(rule, w, r)
-
-			if !s.checkProxyTrust(ctx) {
-				return
-			}
-
-			s.writeHuanProxyHeader(ctx)
-
-			if rule.Type == rulescompile.ProxyTypeFile {
-				s.fileServer(ctx)
-			} else if rule.Type == rulescompile.ProxyTypeDir {
-				s.dirServer(ctx)
-			} else if rule.Type == rulescompile.ProxyTypeAPI {
-				s.apiServer(ctx)
-			} else if rule.Type == rulescompile.ProxyTypeRedirect {
-				s.redirectServer(ctx)
-			} else {
-				s.abortServerError(ctx)
-			}
-
-			if config.GetConfig().NotAbort.IsEnable(false) {
-				_ = ctx.Reset()
-				continue RuleCycle
-			}
-
-			ctx.MustWriteToResponse()
-			return
-
-		}
-		s.defaultResponse(w)
-	}()
-}

+ 0 - 27
src/server/redirect.go

@@ -1,27 +0,0 @@
-package server
-
-import (
-	"fmt"
-	"github.com/SongZihuan/huan-proxy/src/config/rulescompile/actioncompile/rewritecompile"
-	"net/url"
-)
-
-func (s *HuanProxyServer) redirectServer(ctx *Context) {
-	target := s.redirectRewrite(ctx.Rule.Redirect.Address, ctx.Rule.Redirect.Rewrite)
-
-	if _, err := url.Parse(target); err != nil {
-		s.abortServerError(ctx)
-		return
-	}
-
-	fmt.Printf("target: %s\n", target)
-	s.statusRedirect(ctx, target, ctx.Rule.Redirect.Code)
-}
-
-func (s *HuanProxyServer) redirectRewrite(address string, rewrite *rewritecompile.RewriteCompileConfig) string {
-	if rewrite.Use && rewrite.Regex != nil {
-		rewrite.Regex.ReplaceAllString(address, rewrite.Target)
-	}
-
-	return address
-}

+ 1 - 1
src/server/request.go → src/server/request/proxyrequest/request.go

@@ -1,4 +1,4 @@
-package server
+package proxyrequest
 
 import (
 	"github.com/SongZihuan/huan-proxy/src/utils"

+ 1 - 1
src/server/readonlyrequests.go → src/server/request/readonlyrequest/request.go

@@ -1,4 +1,4 @@
-package server
+package readonlyrequest
 
 import (
 	"github.com/SongZihuan/huan-proxy/src/utils"

+ 154 - 0
src/server/responsewriter/writer.go

@@ -0,0 +1,154 @@
+package responsewriter
+
+import (
+	"bytes"
+	"errors"
+	"fmt"
+	"net/http"
+)
+
+var ErrHasWriter = fmt.Errorf("ResponseWriter has been written")
+
+type ResponseWriter struct {
+	writer http.ResponseWriter
+
+	status int
+	buffer bytes.Buffer
+	header http.Header
+	size   int64
+
+	writtenStatus bool
+	writtenBody   bool
+	writtenHeader bool
+	written       bool
+}
+
+func NewResponseWriter(w http.ResponseWriter) *ResponseWriter {
+	if writer, ok := w.(*ResponseWriter); ok {
+		return writer
+	}
+
+	return &ResponseWriter{
+		writer: w,
+
+		status: 0,
+		header: w.Header().Clone(),
+
+		written: false,
+	}
+}
+
+func (r *ResponseWriter) Size() int64 {
+	return r.size
+}
+
+func (r *ResponseWriter) Status() int {
+	return r.status
+}
+
+func (r *ResponseWriter) Write(p []byte) (int, error) {
+	if r.written || r.writtenBody {
+		return 0, ErrHasWriter
+	}
+
+	return r.buffer.Write(p)
+}
+
+func (r *ResponseWriter) WriteHeader(statusCode int) {
+	if r.written {
+		return
+	}
+
+	fmt.Printf("Set Status is: %d\n", r.status)
+	r.status = statusCode
+}
+
+func (r *ResponseWriter) ServerError() {
+	if r.written || r.writtenStatus {
+		return
+	}
+
+	r.status = http.StatusInternalServerError
+	r.writer.WriteHeader(r.status)
+	r.writtenStatus = true
+	r.written = true
+
+	fmt.Printf("Server Error Status is: %d\n", r.status)
+}
+
+func (r *ResponseWriter) Header() http.Header {
+	if r.written {
+		return nil
+	}
+
+	return r.header
+}
+
+func (r *ResponseWriter) Reset() error {
+	if r.written {
+		return ErrHasWriter
+	}
+
+	r.status = 0
+	r.buffer.Reset()
+	r.header = r.writer.Header()
+	r.written = false
+
+	return nil
+}
+
+func (r *ResponseWriter) WriteToResponse() error {
+	if r.written {
+		return ErrHasWriter
+	}
+
+	if !r.writtenBody {
+		_, err := r.writer.Write(r.buffer.Bytes())
+		if err != nil {
+			return err
+		}
+		r.size = int64(r.buffer.Len())
+		r.buffer.Reset() // 清理
+		r.writtenBody = true
+	}
+
+	if !r.writtenHeader {
+		writerHeader := r.writer.Header()
+		for n, h := range r.header {
+			nh := make([]string, 0, len(h))
+			copy(nh, h)
+			writerHeader[n] = nh
+		}
+
+		delHeader := make([]string, 0, 10)
+		for n, _ := range writerHeader {
+			if _, ok := r.header[n]; !ok {
+				delHeader = append(delHeader, n)
+			}
+		}
+
+		for _, n := range delHeader {
+			delete(writerHeader, n)
+		}
+		r.writtenHeader = false
+	}
+
+	// status 放在最后写入
+	if !r.writtenStatus {
+		r.writer.WriteHeader(r.status)
+		r.writtenStatus = true
+		fmt.Printf("Write Status is: %d\n", r.status)
+	}
+
+	r.written = true
+	return nil
+}
+
+func (r *ResponseWriter) MustWriteToResponse() {
+	err := r.WriteToResponse()
+	if err == nil || errors.Is(err, ErrHasWriter) {
+		return
+	}
+
+	r.ServerError()
+}

+ 0 - 122
src/server/writer.go

@@ -1,122 +0,0 @@
-package server
-
-import (
-	"bytes"
-	"fmt"
-	"net/http"
-)
-
-var ErrHasWriter = fmt.Errorf("ResponseWriter has been written")
-
-type ResponseWriter struct {
-	writer http.ResponseWriter
-
-	status int
-	buffer bytes.Buffer
-	header http.Header
-
-	written bool
-}
-
-func NewResponseWriter(w http.ResponseWriter) http.ResponseWriter {
-	if _, ok := w.(*ResponseWriter); ok {
-		return w
-	}
-
-	return &ResponseWriter{
-		writer: w,
-
-		status: 0,
-		header: w.Header().Clone(),
-
-		written: false,
-	}
-}
-
-func (r *ResponseWriter) Size() int64 {
-	return int64(r.buffer.Len())
-}
-
-func (r *ResponseWriter) Status() int {
-	return r.status
-}
-
-func (r *ResponseWriter) Write(p []byte) (int, error) {
-	if r.written {
-		return 0, ErrHasWriter
-	}
-
-	return r.buffer.Write(p)
-}
-
-func (r *ResponseWriter) WriteHeader(statusCode int) {
-	if r.written {
-		return
-	}
-
-	r.status = statusCode
-}
-
-func (r *ResponseWriter) Header() http.Header {
-	if r.written {
-		return nil
-	}
-
-	return r.header
-}
-
-func (r *ResponseWriter) Reset() error {
-	if r.written {
-		return ErrHasWriter
-	}
-
-	r.status = 0
-	r.buffer.Reset()
-	r.header = r.writer.Header()
-	r.written = false
-
-	return nil
-}
-
-func (r *ResponseWriter) WriteToResponse() error {
-	if r.written {
-		return nil
-	}
-
-	_, err := r.writer.Write(r.buffer.Bytes())
-	if err != nil {
-		return err
-	}
-
-	r.writer.WriteHeader(r.status)
-
-	writerHeader := r.writer.Header()
-	for n, h := range r.header {
-		nh := make([]string, 0, len(h))
-		copy(nh, h)
-		writerHeader[n] = nh
-	}
-
-	delHeader := make([]string, 0, 10)
-	for n, _ := range writerHeader {
-		if _, ok := r.header[n]; !ok {
-			delHeader = append(delHeader, n)
-		}
-	}
-
-	for _, n := range delHeader {
-		delete(writerHeader, n)
-	}
-
-	r.written = true
-	return nil
-}
-
-func (r *ResponseWriter) MustWriteToResponse() {
-	err := r.WriteToResponse()
-	if err == nil {
-		return
-	}
-
-	r.writer.WriteHeader(http.StatusInternalServerError)
-}