mirror of
https://github.com/TeaOSLab/EdgeNode.git
synced 2025-11-03 23:20:25 +08:00
静态文件分发也支持压缩、WebP转换
This commit is contained in:
@@ -51,7 +51,7 @@ func (this *HTTPRequest) doRoot() (isBreak bool) {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
rootDir := this.web.Root.Dir
|
var rootDir = this.web.Root.Dir
|
||||||
if this.web.Root.HasVariables() {
|
if this.web.Root.HasVariables() {
|
||||||
rootDir = this.Format(rootDir)
|
rootDir = this.Format(rootDir)
|
||||||
}
|
}
|
||||||
@@ -59,9 +59,9 @@ func (this *HTTPRequest) doRoot() (isBreak bool) {
|
|||||||
rootDir = Tea.Root + Tea.DS + rootDir
|
rootDir = Tea.Root + Tea.DS + rootDir
|
||||||
}
|
}
|
||||||
|
|
||||||
requestPath := this.uri
|
var requestPath = this.uri
|
||||||
|
|
||||||
questionMarkIndex := strings.Index(this.uri, "?")
|
var questionMarkIndex = strings.Index(this.uri, "?")
|
||||||
if questionMarkIndex > -1 {
|
if questionMarkIndex > -1 {
|
||||||
requestPath = this.uri[:questionMarkIndex]
|
requestPath = this.uri[:questionMarkIndex]
|
||||||
}
|
}
|
||||||
@@ -75,7 +75,9 @@ func (this *HTTPRequest) doRoot() (isBreak bool) {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
requestPath = p
|
requestPath = p
|
||||||
} else {
|
} else {
|
||||||
logs.Error(err)
|
if !this.canIgnore(err) {
|
||||||
|
logs.Error(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,8 +94,8 @@ func (this *HTTPRequest) doRoot() (isBreak bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
filename := strings.Replace(requestPath, "/", Tea.DS, -1)
|
var filename = strings.Replace(requestPath, "/", Tea.DS, -1)
|
||||||
filePath := ""
|
var filePath = ""
|
||||||
if len(filename) > 0 && filename[0:1] == Tea.DS {
|
if len(filename) > 0 && filename[0:1] == Tea.DS {
|
||||||
filePath = rootDir + filename
|
filePath = rootDir + filename
|
||||||
} else {
|
} else {
|
||||||
@@ -113,7 +115,9 @@ func (this *HTTPRequest) doRoot() (isBreak bool) {
|
|||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
this.write50x(err, http.StatusInternalServerError, true)
|
this.write50x(err, http.StatusInternalServerError, true)
|
||||||
logs.Error(err)
|
if !this.canIgnore(err) {
|
||||||
|
logs.Error(err)
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -142,7 +146,9 @@ func (this *HTTPRequest) doRoot() (isBreak bool) {
|
|||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
this.write50x(err, http.StatusInternalServerError, true)
|
this.write50x(err, http.StatusInternalServerError, true)
|
||||||
logs.Error(err)
|
if !this.canIgnore(err) {
|
||||||
|
logs.Error(err)
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -152,24 +158,24 @@ func (this *HTTPRequest) doRoot() (isBreak bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 响应header
|
// 响应header
|
||||||
respHeader := this.writer.Header()
|
var respHeader = this.writer.Header()
|
||||||
|
|
||||||
// mime type
|
// mime type
|
||||||
contentType := ""
|
var contentType = ""
|
||||||
if this.web.ResponseHeaderPolicy == nil || !this.web.ResponseHeaderPolicy.IsOn || !this.web.ResponseHeaderPolicy.ContainsHeader("CONTENT-TYPE") {
|
if this.web.ResponseHeaderPolicy == nil || !this.web.ResponseHeaderPolicy.IsOn || !this.web.ResponseHeaderPolicy.ContainsHeader("CONTENT-TYPE") {
|
||||||
ext := filepath.Ext(filePath)
|
var ext = filepath.Ext(filePath)
|
||||||
if len(ext) > 0 {
|
if len(ext) > 0 {
|
||||||
mimeType := mime.TypeByExtension(ext)
|
mimeType := mime.TypeByExtension(ext)
|
||||||
if len(mimeType) > 0 {
|
if len(mimeType) > 0 {
|
||||||
semicolonIndex := strings.Index(mimeType, ";")
|
var semicolonIndex = strings.Index(mimeType, ";")
|
||||||
mimeTypeKey := mimeType
|
var mimeTypeKey = mimeType
|
||||||
if semicolonIndex > 0 {
|
if semicolonIndex > 0 {
|
||||||
mimeTypeKey = mimeType[:semicolonIndex]
|
mimeTypeKey = mimeType[:semicolonIndex]
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, found := textMimeMap[mimeTypeKey]; found {
|
if _, found := textMimeMap[mimeTypeKey]; found {
|
||||||
if this.web.Charset != nil && this.web.Charset.IsOn && len(this.web.Charset.Charset) > 0 {
|
if this.web.Charset != nil && this.web.Charset.IsOn && len(this.web.Charset.Charset) > 0 {
|
||||||
charset := this.web.Charset.Charset
|
var charset = this.web.Charset.Charset
|
||||||
if this.web.Charset.IsUpper {
|
if this.web.Charset.IsUpper {
|
||||||
charset = strings.ToUpper(charset)
|
charset = strings.ToUpper(charset)
|
||||||
}
|
}
|
||||||
@@ -197,7 +203,7 @@ func (this *HTTPRequest) doRoot() (isBreak bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 支持 ETag
|
// 支持 ETag
|
||||||
eTag := "\"e" + fmt.Sprintf("%0x", xxhash.Sum64String(filename+strconv.FormatInt(stat.ModTime().UnixNano(), 10)+strconv.FormatInt(stat.Size(), 10))) + "\""
|
var eTag = "\"e" + fmt.Sprintf("%0x", xxhash.Sum64String(filename+strconv.FormatInt(stat.ModTime().UnixNano(), 10)+strconv.FormatInt(stat.Size(), 10))) + "\""
|
||||||
if len(respHeader.Get("ETag")) == 0 {
|
if len(respHeader.Get("ETag")) == 0 {
|
||||||
respHeader.Set("ETag", eTag)
|
respHeader.Set("ETag", eTag)
|
||||||
}
|
}
|
||||||
@@ -227,7 +233,7 @@ func (this *HTTPRequest) doRoot() (isBreak bool) {
|
|||||||
// 支持Range
|
// 支持Range
|
||||||
respHeader.Set("Accept-Ranges", "bytes")
|
respHeader.Set("Accept-Ranges", "bytes")
|
||||||
ifRangeHeaders, ok := this.RawReq.Header["If-Range"]
|
ifRangeHeaders, ok := this.RawReq.Header["If-Range"]
|
||||||
supportRange := true
|
var supportRange = true
|
||||||
if ok {
|
if ok {
|
||||||
supportRange = false
|
supportRange = false
|
||||||
for _, v := range ifRangeHeaders {
|
for _, v := range ifRangeHeaders {
|
||||||
@@ -244,7 +250,7 @@ func (this *HTTPRequest) doRoot() (isBreak bool) {
|
|||||||
// 支持Range
|
// 支持Range
|
||||||
var ranges = []rangeutils.Range{}
|
var ranges = []rangeutils.Range{}
|
||||||
if supportRange {
|
if supportRange {
|
||||||
contentRange := this.RawReq.Header.Get("Range")
|
var contentRange = this.RawReq.Header.Get("Range")
|
||||||
if len(contentRange) > 0 {
|
if len(contentRange) > 0 {
|
||||||
if fileSize == 0 {
|
if fileSize == 0 {
|
||||||
this.processResponseHeaders(http.StatusRequestedRangeNotSatisfiable)
|
this.processResponseHeaders(http.StatusRequestedRangeNotSatisfiable)
|
||||||
@@ -277,7 +283,7 @@ func (this *HTTPRequest) doRoot() (isBreak bool) {
|
|||||||
respHeader.Set("Content-Length", strconv.FormatInt(fileSize, 10))
|
respHeader.Set("Content-Length", strconv.FormatInt(fileSize, 10))
|
||||||
}
|
}
|
||||||
|
|
||||||
reader, 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, true)
|
||||||
return true
|
return true
|
||||||
@@ -291,12 +297,16 @@ func (this *HTTPRequest) doRoot() (isBreak bool) {
|
|||||||
this.cacheRef = nil // 不支持缓存
|
this.cacheRef = nil // 不支持缓存
|
||||||
}
|
}
|
||||||
|
|
||||||
this.writer.Prepare(nil, fileSize, http.StatusOK, true)
|
var resp = &http.Response{
|
||||||
|
ContentLength: fileSize,
|
||||||
|
Body: fileReader,
|
||||||
|
StatusCode: http.StatusOK,
|
||||||
|
}
|
||||||
|
this.writer.Prepare(resp, fileSize, http.StatusOK, true)
|
||||||
|
|
||||||
pool := this.bytePool(fileSize)
|
var pool = this.bytePool(fileSize)
|
||||||
buf := pool.Get()
|
var buf = pool.Get()
|
||||||
defer func() {
|
defer func() {
|
||||||
_ = reader.Close()
|
|
||||||
pool.Put(buf)
|
pool.Put(buf)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@@ -304,12 +314,14 @@ func (this *HTTPRequest) doRoot() (isBreak bool) {
|
|||||||
respHeader.Set("Content-Range", ranges[0].ComposeContentRangeHeader(types.String(fileSize)))
|
respHeader.Set("Content-Range", ranges[0].ComposeContentRangeHeader(types.String(fileSize)))
|
||||||
this.writer.WriteHeader(http.StatusPartialContent)
|
this.writer.WriteHeader(http.StatusPartialContent)
|
||||||
|
|
||||||
ok, err := httpRequestReadRange(reader, buf, ranges[0].Start(), ranges[0].End(), func(buf []byte, n int) error {
|
ok, err := httpRequestReadRange(resp.Body, buf, ranges[0].Start(), ranges[0].End(), func(buf []byte, n int) error {
|
||||||
_, err := this.writer.Write(buf[:n])
|
_, err := this.writer.Write(buf[:n])
|
||||||
return err
|
return err
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logs.Error(err)
|
if !this.canIgnore(err) {
|
||||||
|
logs.Error(err)
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if !ok {
|
if !ok {
|
||||||
@@ -318,7 +330,7 @@ func (this *HTTPRequest) doRoot() (isBreak bool) {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
} else if len(ranges) > 1 {
|
} else if len(ranges) > 1 {
|
||||||
boundary := httpRequestGenBoundary()
|
var boundary = httpRequestGenBoundary()
|
||||||
respHeader.Set("Content-Type", "multipart/byteranges; boundary="+boundary)
|
respHeader.Set("Content-Type", "multipart/byteranges; boundary="+boundary)
|
||||||
|
|
||||||
this.writer.WriteHeader(http.StatusPartialContent)
|
this.writer.WriteHeader(http.StatusPartialContent)
|
||||||
@@ -330,30 +342,38 @@ func (this *HTTPRequest) doRoot() (isBreak bool) {
|
|||||||
_, err = this.writer.WriteString("\r\n--" + boundary + "\r\n")
|
_, err = this.writer.WriteString("\r\n--" + boundary + "\r\n")
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logs.Error(err)
|
if !this.canIgnore(err) {
|
||||||
|
logs.Error(err)
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = this.writer.WriteString("Content-Range: " + r.ComposeContentRangeHeader(types.String(fileSize)) + "\r\n")
|
_, err = this.writer.WriteString("Content-Range: " + r.ComposeContentRangeHeader(types.String(fileSize)) + "\r\n")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logs.Error(err)
|
if !this.canIgnore(err) {
|
||||||
|
logs.Error(err)
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(contentType) > 0 {
|
if len(contentType) > 0 {
|
||||||
_, err = this.writer.WriteString("Content-Type: " + contentType + "\r\n\r\n")
|
_, err = this.writer.WriteString("Content-Type: " + contentType + "\r\n\r\n")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logs.Error(err)
|
if !this.canIgnore(err) {
|
||||||
|
logs.Error(err)
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ok, err := httpRequestReadRange(reader, buf, r.Start(), r.End(), func(buf []byte, n int) error {
|
ok, err := httpRequestReadRange(resp.Body, buf, r.Start(), r.End(), func(buf []byte, n int) error {
|
||||||
_, err := this.writer.Write(buf[:n])
|
_, err := this.writer.Write(buf[:n])
|
||||||
return err
|
return err
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logs.Error(err)
|
if !this.canIgnore(err) {
|
||||||
|
logs.Error(err)
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if !ok {
|
if !ok {
|
||||||
@@ -365,14 +385,17 @@ func (this *HTTPRequest) doRoot() (isBreak bool) {
|
|||||||
|
|
||||||
_, err = this.writer.WriteString("\r\n--" + boundary + "--\r\n")
|
_, err = this.writer.WriteString("\r\n--" + boundary + "--\r\n")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logs.Error(err)
|
if !this.canIgnore(err) {
|
||||||
|
logs.Error(err)
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
_, err = io.CopyBuffer(this.writer, reader, buf)
|
_, err = io.CopyBuffer(this.writer, resp.Body, buf)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logs.Error(err)
|
if !this.canIgnore(err) {
|
||||||
|
logs.Error(err)
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -400,7 +423,9 @@ func (this *HTTPRequest) findIndexFile(dir string) (filename string, stat os.Fil
|
|||||||
if strings.Contains(index, "*") {
|
if strings.Contains(index, "*") {
|
||||||
indexFiles, err := filepath.Glob(dir + Tea.DS + index)
|
indexFiles, err := filepath.Glob(dir + Tea.DS + index)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logs.Error(err)
|
if !this.canIgnore(err) {
|
||||||
|
logs.Error(err)
|
||||||
|
}
|
||||||
this.addError(err)
|
this.addError(err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -449,7 +449,9 @@ func (this *HTTPWriter) PrepareCache(resp *http.Response, size int64) {
|
|||||||
this.rawReader = cacheReader
|
this.rawReader = cacheReader
|
||||||
|
|
||||||
cacheReader.OnFail(func(err error) {
|
cacheReader.OnFail(func(err error) {
|
||||||
_ = this.cacheWriter.Discard()
|
if this.cacheWriter != nil {
|
||||||
|
_ = this.cacheWriter.Discard()
|
||||||
|
}
|
||||||
this.cacheWriter = nil
|
this.cacheWriter = nil
|
||||||
})
|
})
|
||||||
cacheReader.OnEOF(func() {
|
cacheReader.OnEOF(func() {
|
||||||
@@ -860,6 +862,70 @@ func (this *HTTPWriter) SetOk() {
|
|||||||
|
|
||||||
// Close 关闭
|
// Close 关闭
|
||||||
func (this *HTTPWriter) Close() {
|
func (this *HTTPWriter) Close() {
|
||||||
|
this.finishWebP()
|
||||||
|
this.finishRequest()
|
||||||
|
this.finishCache()
|
||||||
|
this.finishCompression()
|
||||||
|
|
||||||
|
// 统计
|
||||||
|
if this.sentBodyBytes == 0 {
|
||||||
|
this.sentBodyBytes = this.counterWriter.TotalBytes()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hijack Hijack
|
||||||
|
func (this *HTTPWriter) Hijack() (conn net.Conn, buf *bufio.ReadWriter, err error) {
|
||||||
|
hijack, ok := this.rawWriter.(http.Hijacker)
|
||||||
|
if ok {
|
||||||
|
return hijack.Hijack()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flush Flush
|
||||||
|
func (this *HTTPWriter) Flush() {
|
||||||
|
flusher, ok := this.rawWriter.(http.Flusher)
|
||||||
|
if ok {
|
||||||
|
flusher.Flush()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DelayRead 是否延迟读取Reader
|
||||||
|
func (this *HTTPWriter) DelayRead() bool {
|
||||||
|
return this.delayRead
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算stale时长
|
||||||
|
func (this *HTTPWriter) calculateStaleLife() int {
|
||||||
|
var staleLife = 600 // TODO 可以在缓存策略里设置此时间
|
||||||
|
var staleConfig = this.req.web.Cache.Stale
|
||||||
|
if staleConfig != nil && staleConfig.IsOn {
|
||||||
|
// 从Header中读取stale-if-error
|
||||||
|
var isDefinedInHeader = false
|
||||||
|
if staleConfig.SupportStaleIfErrorHeader {
|
||||||
|
var cacheControl = this.GetHeader("Cache-Control")
|
||||||
|
var pieces = strings.Split(cacheControl, ",")
|
||||||
|
for _, piece := range pieces {
|
||||||
|
var eqIndex = strings.Index(piece, "=")
|
||||||
|
if eqIndex > 0 && strings.TrimSpace(piece[:eqIndex]) == "stale-if-error" {
|
||||||
|
// 这里预示着如果stale-if-error=0,可以关闭stale功能
|
||||||
|
staleLife = types.Int(strings.TrimSpace(piece[eqIndex+1:]))
|
||||||
|
isDefinedInHeader = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 自定义
|
||||||
|
if !isDefinedInHeader && staleConfig.Life != nil {
|
||||||
|
staleLife = types.Int(staleConfig.Life.Duration().Seconds())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return staleLife
|
||||||
|
}
|
||||||
|
|
||||||
|
// 结束WebP
|
||||||
|
func (this *HTTPWriter) finishWebP() {
|
||||||
// 处理WebP
|
// 处理WebP
|
||||||
if this.webpIsEncoding {
|
if this.webpIsEncoding {
|
||||||
var webpCacheWriter caches.Writer
|
var webpCacheWriter caches.Writer
|
||||||
@@ -920,6 +986,7 @@ func (this *HTTPWriter) Close() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
// 发生了错误终止处理
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -949,7 +1016,7 @@ func (this *HTTPWriter) Close() {
|
|||||||
//webpConfig.SetLossless(1)
|
//webpConfig.SetLossless(1)
|
||||||
webpConfig.SetQuality(f)
|
webpConfig.SetQuality(f)
|
||||||
|
|
||||||
timeline := 0
|
var timeline = 0
|
||||||
|
|
||||||
for i, img := range gifImage.Image {
|
for i, img := range gifImage.Image {
|
||||||
err = anim.AddFrame(img, timeline, webpConfig)
|
err = anim.AddFrame(img, timeline, webpConfig)
|
||||||
@@ -989,15 +1056,10 @@ func (this *HTTPWriter) Close() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if this.writer != nil {
|
// 结束缓存相关处理
|
||||||
_ = this.writer.Close()
|
func (this *HTTPWriter) finishCache() {
|
||||||
}
|
|
||||||
|
|
||||||
if this.rawReader != nil {
|
|
||||||
_ = this.rawReader.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 缓存
|
// 缓存
|
||||||
if this.cacheWriter != nil {
|
if this.cacheWriter != nil {
|
||||||
if this.isOk && this.cacheIsFinished {
|
if this.isOk && this.cacheIsFinished {
|
||||||
@@ -1055,7 +1117,10 @@ func (this *HTTPWriter) Close() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 结束压缩相关处理
|
||||||
|
func (this *HTTPWriter) finishCompression() {
|
||||||
if this.compressionCacheWriter != nil {
|
if this.compressionCacheWriter != nil {
|
||||||
if this.isOk {
|
if this.isOk {
|
||||||
err := this.compressionCacheWriter.Close()
|
err := this.compressionCacheWriter.Close()
|
||||||
@@ -1076,59 +1141,15 @@ func (this *HTTPWriter) Close() {
|
|||||||
_ = this.compressionCacheWriter.Discard()
|
_ = this.compressionCacheWriter.Discard()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if this.sentBodyBytes == 0 {
|
// 最终关闭
|
||||||
this.sentBodyBytes = this.counterWriter.TotalBytes()
|
func (this *HTTPWriter) finishRequest() {
|
||||||
|
if this.writer != nil {
|
||||||
|
_ = this.writer.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
if this.rawReader != nil {
|
||||||
|
_ = this.rawReader.Close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hijack Hijack
|
|
||||||
func (this *HTTPWriter) Hijack() (conn net.Conn, buf *bufio.ReadWriter, err error) {
|
|
||||||
hijack, ok := this.rawWriter.(http.Hijacker)
|
|
||||||
if ok {
|
|
||||||
return hijack.Hijack()
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Flush Flush
|
|
||||||
func (this *HTTPWriter) Flush() {
|
|
||||||
flusher, ok := this.rawWriter.(http.Flusher)
|
|
||||||
if ok {
|
|
||||||
flusher.Flush()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// DelayRead 是否延迟读取Reader
|
|
||||||
func (this *HTTPWriter) DelayRead() bool {
|
|
||||||
return this.delayRead
|
|
||||||
}
|
|
||||||
|
|
||||||
// 计算stale时长
|
|
||||||
func (this *HTTPWriter) calculateStaleLife() int {
|
|
||||||
var staleLife = 600 // TODO 可以在缓存策略里设置此时间
|
|
||||||
var staleConfig = this.req.web.Cache.Stale
|
|
||||||
if staleConfig != nil && staleConfig.IsOn {
|
|
||||||
// 从Header中读取stale-if-error
|
|
||||||
var isDefinedInHeader = false
|
|
||||||
if staleConfig.SupportStaleIfErrorHeader {
|
|
||||||
var cacheControl = this.GetHeader("Cache-Control")
|
|
||||||
var pieces = strings.Split(cacheControl, ",")
|
|
||||||
for _, piece := range pieces {
|
|
||||||
var eqIndex = strings.Index(piece, "=")
|
|
||||||
if eqIndex > 0 && strings.TrimSpace(piece[:eqIndex]) == "stale-if-error" {
|
|
||||||
// 这里预示着如果stale-if-error=0,可以关闭stale功能
|
|
||||||
staleLife = types.Int(strings.TrimSpace(piece[eqIndex+1:]))
|
|
||||||
isDefinedInHeader = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 自定义
|
|
||||||
if !isDefinedInHeader && staleConfig.Life != nil {
|
|
||||||
staleLife = types.Int(staleConfig.Life.Duration().Seconds())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return staleLife
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user