40x, 50x提示默认使用HTML;50x提示增加原因信息

This commit is contained in:
GoEdgeLab
2022-07-30 10:48:41 +08:00
parent af5c212a01
commit 5c40fcf2b2
8 changed files with 93 additions and 39 deletions

View File

@@ -151,7 +151,7 @@ func (this *HTTPRequest) Do() {
// Web配置 // Web配置
err := this.configureWeb(this.ReqServer.Web, true, 0) err := this.configureWeb(this.ReqServer.Web, true, 0)
if err != nil { if err != nil {
this.write50x(err, http.StatusInternalServerError, false) this.write50x(err, http.StatusInternalServerError, "Failed to configure the server", "配置服务失败", false)
this.doEnd() this.doEnd()
return return
} }
@@ -286,7 +286,7 @@ func (this *HTTPRequest) doBegin() {
var err error var err error
this.requestBodyData, err = ioutil.ReadAll(io.LimitReader(this.RawReq.Body, AccessLogMaxRequestBodySize)) this.requestBodyData, err = ioutil.ReadAll(io.LimitReader(this.RawReq.Body, AccessLogMaxRequestBodySize))
if err != nil { if err != nil {
this.write50x(err, http.StatusBadGateway, false) this.write50x(err, http.StatusBadGateway, "Failed to read request body for access log", "为访问日志读取请求Body失败", false)
return return
} }
this.RawReq.Body = ioutil.NopCloser(io.MultiReader(bytes.NewBuffer(this.requestBodyData), this.RawReq.Body)) this.RawReq.Body = ioutil.NopCloser(io.MultiReader(bytes.NewBuffer(this.requestBodyData), this.RawReq.Body))

View File

@@ -33,7 +33,7 @@ func (this *HTTPRequest) doAuth() (shouldStop bool) {
return writer.StatusCode(), nil return writer.StatusCode(), nil
}, this.Format) }, this.Format)
if err != nil { if err != nil {
this.write50x(err, http.StatusInternalServerError, false) this.write50x(err, http.StatusInternalServerError, "Failed to execute the AuthPolicy", "认证策略执行失败", false)
return return
} }
if b { if b {

View File

@@ -1,32 +1,59 @@
package nodes package nodes
import ( import (
"github.com/TeaOSLab/EdgeCommon/pkg/configutils"
"github.com/iwind/TeaGo/lists" "github.com/iwind/TeaGo/lists"
"github.com/iwind/TeaGo/types" "github.com/iwind/TeaGo/types"
"net/http" "net/http"
"strings"
) )
const httpStatusPageTemplate = `<!DOCTYPE html>
<html>
<head>
<title>${status} ${statusMessage}</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
</head>
<body>
<h1>${status} ${statusMessage}</h1>
<p>${message}</p>
<address>Request ID: ${requestId}.</address>
</body>
</html>`
func (this *HTTPRequest) write404() { func (this *HTTPRequest) write404() {
if this.doPage(http.StatusNotFound) { this.writeCode(http.StatusNotFound)
}
func (this *HTTPRequest) writeCode(statusCode int) {
if this.doPage(statusCode) {
return return
} }
this.processResponseHeaders(http.StatusNotFound) var pageContent = configutils.ParseVariables(httpStatusPageTemplate, func(varName string) (value string) {
this.writer.WriteHeader(http.StatusNotFound) switch varName {
_, _ = this.writer.Write([]byte("404 page not found: '" + this.URL() + "'" + " (Request Id: " + this.requestId + ")")) case "status":
return types.String(statusCode)
case "statusMessage":
return http.StatusText(statusCode)
case "requestId":
return this.requestId
case "message":
return "" // 空
}
return "${" + varName + "}"
})
this.processResponseHeaders(statusCode)
this.writer.WriteHeader(statusCode)
_, _ = this.writer.Write([]byte(pageContent))
} }
func (this *HTTPRequest) writeCode(code int) { func (this *HTTPRequest) write50x(err error, statusCode int, enMessage string, zhMessage string, canTryStale bool) {
if this.doPage(code) {
return
}
this.processResponseHeaders(code)
this.writer.WriteHeader(code)
_, _ = this.writer.Write([]byte(types.String(code) + " " + http.StatusText(code) + ": '" + this.URL() + "'" + " (Request Id: " + this.requestId + ")"))
}
func (this *HTTPRequest) write50x(err error, statusCode int, canTryStale bool) {
if err != nil { if err != nil {
this.addError(err) this.addError(err)
} }
@@ -37,7 +64,7 @@ func (this *HTTPRequest) write50x(err error, statusCode int, canTryStale bool) {
this.web.Cache.Stale != nil && this.web.Cache.Stale != nil &&
this.web.Cache.Stale.IsOn && this.web.Cache.Stale.IsOn &&
(len(this.web.Cache.Stale.Status) == 0 || lists.ContainsInt(this.web.Cache.Stale.Status, statusCode)) { (len(this.web.Cache.Stale.Status) == 0 || lists.ContainsInt(this.web.Cache.Stale.Status, statusCode)) {
ok := this.doCacheRead(true) var ok = this.doCacheRead(true)
if ok { if ok {
return return
} }
@@ -47,7 +74,34 @@ func (this *HTTPRequest) write50x(err error, statusCode int, canTryStale bool) {
if this.doPage(statusCode) { if this.doPage(statusCode) {
return return
} }
// 内置HTML模板
var pageContent = configutils.ParseVariables(httpStatusPageTemplate, func(varName string) (value string) {
switch varName {
case "status":
return types.String(statusCode)
case "statusMessage":
return http.StatusText(statusCode)
case "requestId":
return this.requestId
case "message":
var acceptLanguages = this.RawReq.Header.Get("Accept-Language")
if len(acceptLanguages) > 0 {
var index = strings.Index(acceptLanguages, ",")
if index > 0 {
var firstLanguage = acceptLanguages[:index]
if firstLanguage == "zh-CN" {
return "网站出了一点小问题,原因:" + zhMessage + "。"
}
}
}
return "The site is unavailable now, cause: " + enMessage + "."
}
return "${" + varName + "}"
})
this.processResponseHeaders(statusCode) this.processResponseHeaders(statusCode)
this.writer.WriteHeader(statusCode) this.writer.WriteHeader(statusCode)
_, _ = this.writer.Write([]byte(types.String(statusCode) + " " + http.StatusText(statusCode) + " (Request Id: " + this.requestId + ")"))
_, _ = this.writer.Write([]byte(pageContent))
} }

View File

@@ -81,7 +81,7 @@ func (this *HTTPRequest) doFastcgi() (shouldStop bool) {
client, err := fcgi.SharedPool(fastcgi.Network(), fastcgi.RealAddress(), uint(poolSize)).Client() client, err := fcgi.SharedPool(fastcgi.Network(), fastcgi.RealAddress(), uint(poolSize)).Client()
if err != nil { if err != nil {
this.write50x(err, http.StatusInternalServerError, false) this.write50x(err, http.StatusInternalServerError, "Failed to create Fastcgi pool", "Fastcgi池生成失败", false)
return return
} }
@@ -159,13 +159,13 @@ func (this *HTTPRequest) doFastcgi() (shouldStop bool) {
resp, stderr, err := client.Call(fcgiReq) resp, stderr, err := client.Call(fcgiReq)
if err != nil { if err != nil {
this.write50x(err, http.StatusInternalServerError, false) this.write50x(err, http.StatusInternalServerError, "Failed to read Fastcgi", "读取Fastcgi失败", false)
return return
} }
if len(stderr) > 0 { if len(stderr) > 0 {
err := errors.New("Fastcgi Error: " + strings.TrimSpace(string(stderr)) + " script: " + maps.NewMap(params).GetString("SCRIPT_FILENAME")) err := errors.New("Fastcgi Error: " + strings.TrimSpace(string(stderr)) + " script: " + maps.NewMap(params).GetString("SCRIPT_FILENAME"))
this.write50x(err, http.StatusInternalServerError, false) this.write50x(err, http.StatusInternalServerError, "Failed to read Fastcgi", "读取Fastcgi失败", false)
return return
} }

View File

@@ -56,7 +56,7 @@ func (this *HTTPRequest) doReverseProxy() {
if origin == nil { if origin == nil {
err := errors.New(this.URL() + ": no available origin sites for reverse proxy") err := errors.New(this.URL() + ": no available origin sites for reverse proxy")
remotelogs.ServerError(this.ReqServer.Id, "HTTP_REQUEST_REVERSE_PROXY", err.Error(), "", nil) remotelogs.ServerError(this.ReqServer.Id, "HTTP_REQUEST_REVERSE_PROXY", err.Error(), "", nil)
this.write50x(err, http.StatusBadGateway, true) this.write50x(err, http.StatusBadGateway, "No origin site yet", "尚未配置源站", true)
return return
} }
@@ -80,7 +80,7 @@ func (this *HTTPRequest) doReverseProxy() {
if origin.Addr == nil { if origin.Addr == nil {
err := errors.New(this.URL() + ": Origin '" + strconv.FormatInt(origin.Id, 10) + "' does not has a address") err := errors.New(this.URL() + ": Origin '" + strconv.FormatInt(origin.Id, 10) + "' does not has a address")
remotelogs.Error("HTTP_REQUEST_REVERSE_PROXY", err.Error()) remotelogs.Error("HTTP_REQUEST_REVERSE_PROXY", err.Error())
this.write50x(err, http.StatusBadGateway, true) this.write50x(err, http.StatusBadGateway, "Origin site did not has a valid address", "源站尚未配置地址", true)
return return
} }
this.RawReq.URL.Scheme = origin.Addr.Protocol.Primary().Scheme() this.RawReq.URL.Scheme = origin.Addr.Protocol.Primary().Scheme()
@@ -132,7 +132,7 @@ func (this *HTTPRequest) doReverseProxy() {
if originHostIndex < 0 { if originHostIndex < 0 {
var originErr = errors.New(this.URL() + ": Invalid origin address '" + originAddr + "', lacking port") var originErr = errors.New(this.URL() + ": Invalid origin address '" + originAddr + "', lacking port")
remotelogs.Error("HTTP_REQUEST_REVERSE_PROXY", originErr.Error()) remotelogs.Error("HTTP_REQUEST_REVERSE_PROXY", originErr.Error())
this.write50x(originErr, http.StatusBadGateway, true) this.write50x(originErr, http.StatusBadGateway, "No port in origin site address", "源站地址中没有配置端口", true)
return return
} }
originAddr = originAddr[:originHostIndex+1] + types.String(this.requestServerPort()) originAddr = originAddr[:originHostIndex+1] + types.String(this.requestServerPort())
@@ -211,7 +211,7 @@ func (this *HTTPRequest) doReverseProxy() {
client, err := SharedHTTPClientPool.Client(this, origin, originAddr, this.reverseProxy.ProxyProtocol, this.reverseProxy.FollowRedirects) client, err := SharedHTTPClientPool.Client(this, origin, originAddr, this.reverseProxy.ProxyProtocol, this.reverseProxy.FollowRedirects)
if err != nil { if err != nil {
remotelogs.Error("HTTP_REQUEST_REVERSE_PROXY", this.URL()+": Create client failed: "+err.Error()) remotelogs.Error("HTTP_REQUEST_REVERSE_PROXY", this.URL()+": Create client failed: "+err.Error())
this.write50x(err, http.StatusBadGateway, true) this.write50x(err, http.StatusBadGateway, "Failed to create origin site client", "构造源站客户端失败", true)
return return
} }
@@ -230,18 +230,18 @@ func (this *HTTPRequest) doReverseProxy() {
SharedOriginStateManager.Fail(origin, requestHost, this.reverseProxy, func() { SharedOriginStateManager.Fail(origin, requestHost, this.reverseProxy, func() {
this.reverseProxy.ResetScheduling() this.reverseProxy.ResetScheduling()
}) })
this.write50x(err, http.StatusBadGateway, true) this.write50x(err, http.StatusBadGateway, "Failed to read origin site", "源站读取失败", true)
remotelogs.Warn("HTTP_REQUEST_REVERSE_PROXY", this.RawReq.URL.String()+": Request origin server failed: "+err.Error()) remotelogs.Warn("HTTP_REQUEST_REVERSE_PROXY", this.RawReq.URL.String()+": Request origin server failed: "+err.Error())
} else if httpErr.Err != context.Canceled { } else if httpErr.Err != context.Canceled {
SharedOriginStateManager.Fail(origin, requestHost, this.reverseProxy, func() { SharedOriginStateManager.Fail(origin, requestHost, this.reverseProxy, func() {
this.reverseProxy.ResetScheduling() this.reverseProxy.ResetScheduling()
}) })
if httpErr.Timeout() { if httpErr.Timeout() {
this.write50x(err, http.StatusGatewayTimeout, true) this.write50x(err, http.StatusGatewayTimeout, "Read origin site timeout", "源站读取超时", true)
} else if httpErr.Temporary() { } else if httpErr.Temporary() {
this.write50x(err, http.StatusServiceUnavailable, true) this.write50x(err, http.StatusServiceUnavailable, "Origin site unavailable now", "源站当前不可用", true)
} else { } else {
this.write50x(err, http.StatusBadGateway, true) this.write50x(err, http.StatusBadGateway, "Failed to read origin site", "源站读取失败", true)
} }
if httpErr.Err != io.EOF { if httpErr.Err != io.EOF {
remotelogs.Warn("HTTP_REQUEST_REVERSE_PROXY", this.URL()+": Request origin server failed: "+err.Error()) remotelogs.Warn("HTTP_REQUEST_REVERSE_PROXY", this.URL()+": Request origin server failed: "+err.Error())
@@ -264,7 +264,7 @@ func (this *HTTPRequest) doReverseProxy() {
} }
if !isClientError { if !isClientError {
this.write50x(err, http.StatusBadGateway, true) this.write50x(err, http.StatusBadGateway, "Failed to read origin site", "源站读取失败", true)
} }
} }
if resp != nil && resp.Body != nil { if resp != nil && resp.Body != nil {

View File

@@ -114,7 +114,7 @@ func (this *HTTPRequest) doRoot() (isBreak bool) {
} }
return return
} else { } else {
this.write50x(err, http.StatusInternalServerError, true) this.write50x(err, http.StatusInternalServerError, "Failed to stat the file", "查看文件统计信息失败", true)
if !this.canIgnore(err) { if !this.canIgnore(err) {
logs.Error(err) logs.Error(err)
} }
@@ -145,7 +145,7 @@ func (this *HTTPRequest) doRoot() (isBreak bool) {
} }
return return
} else { } else {
this.write50x(err, http.StatusInternalServerError, true) this.write50x(err, http.StatusInternalServerError, "Failed to stat the file", "查看文件统计信息失败", true)
if !this.canIgnore(err) { if !this.canIgnore(err) {
logs.Error(err) logs.Error(err)
} }
@@ -285,7 +285,7 @@ func (this *HTTPRequest) doRoot() (isBreak bool) {
fileReader, err := os.OpenFile(filePath, os.O_RDONLY, 0444) fileReader, err := os.OpenFile(filePath, os.O_RDONLY, 0444)
if err != nil { if err != nil {
this.write50x(err, http.StatusInternalServerError, true) this.write50x(err, http.StatusInternalServerError, "Failed to open the file", "试图打开文件失败", true)
return true return true
} }

View File

@@ -35,7 +35,7 @@ func (this *HTTPRequest) doURL(method string, url string, host string, statusCod
resp, err := client.Do(req) resp, err := client.Do(req)
if err != nil { if err != nil {
remotelogs.Error("HTTP_REQUEST_URL", req.URL.String()+": "+err.Error()) remotelogs.Error("HTTP_REQUEST_URL", req.URL.String()+": "+err.Error())
this.write50x(err, http.StatusInternalServerError, false) this.write50x(err, http.StatusInternalServerError, "Failed to read url", "读取URL失败", false)
return return
} }
defer func() { defer func() {

View File

@@ -43,7 +43,7 @@ func (this *HTTPRequest) doWebsocket(requestHost string) {
// TODO 增加N次错误重试重试的时候需要尝试不同的源站 // TODO 增加N次错误重试重试的时候需要尝试不同的源站
originConn, _, err := OriginConnect(this.origin, this.requestServerPort(), this.RawReq.RemoteAddr, requestHost) originConn, _, err := OriginConnect(this.origin, this.requestServerPort(), this.RawReq.RemoteAddr, requestHost)
if err != nil { if err != nil {
this.write50x(err, http.StatusBadGateway, false) this.write50x(err, http.StatusBadGateway, "Failed to connect origin site", "源站连接失败", false)
// 增加失败次数 // 增加失败次数
SharedOriginStateManager.Fail(this.origin, requestHost, this.reverseProxy, func() { SharedOriginStateManager.Fail(this.origin, requestHost, this.reverseProxy, func() {
@@ -65,13 +65,13 @@ func (this *HTTPRequest) doWebsocket(requestHost string) {
err = this.RawReq.Write(originConn) err = this.RawReq.Write(originConn)
if err != nil { if err != nil {
this.write50x(err, http.StatusBadGateway, false) this.write50x(err, http.StatusBadGateway, "Failed to write request to origin site", "源站请求初始化失败", false)
return return
} }
clientConn, _, err := this.writer.Hijack() clientConn, _, err := this.writer.Hijack()
if err != nil || clientConn == nil { if err != nil || clientConn == nil {
this.write50x(err, http.StatusInternalServerError, false) this.write50x(err, http.StatusInternalServerError, "Failed to get origin site connection", "获取源站连接失败", false)
return return
} }
defer func() { defer func() {