mirror of
https://github.com/TeaOSLab/EdgeNode.git
synced 2025-11-11 22:00:25 +08:00
40x, 50x提示默认使用HTML;50x提示增加原因信息
This commit is contained in:
@@ -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))
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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() {
|
||||||
|
|||||||
@@ -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() {
|
||||||
|
|||||||
Reference in New Issue
Block a user