mirror of https://github.com/jlelse/GoBlog
Cache middleware now records the response and writes that to the DB
This commit is contained in:
parent
2639cd9f3b
commit
65ce24d410
51
cache.go
51
cache.go
|
@ -2,7 +2,9 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/json"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
"net/url"
|
"net/url"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
@ -10,18 +12,36 @@ import (
|
||||||
func CacheMiddleware(next http.Handler) http.Handler {
|
func CacheMiddleware(next http.Handler) http.Handler {
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
requestUrl, _ := url.ParseRequestURI(r.RequestURI)
|
requestUrl, _ := url.ParseRequestURI(r.RequestURI)
|
||||||
|
path := SlashTrimmedPath(r)
|
||||||
if appConfig.cache.enable &&
|
if appConfig.cache.enable &&
|
||||||
// Check bypass query
|
// Check bypass query
|
||||||
!(requestUrl != nil && requestUrl.Query().Get("cache") == "0") {
|
!(requestUrl != nil && requestUrl.Query().Get("cache") == "0") {
|
||||||
mime, t, cache := getCache(SlashTrimmedPath(r), r.Context())
|
cacheTime, header, body := getCache(path, r.Context())
|
||||||
if cache == nil {
|
if cacheTime == 0 {
|
||||||
next.ServeHTTP(w, r)
|
recorder := httptest.NewRecorder()
|
||||||
|
next.ServeHTTP(recorder, r)
|
||||||
|
// Copy values from recorder
|
||||||
|
code := recorder.Code
|
||||||
|
// Send response
|
||||||
|
for k, v := range recorder.Header() {
|
||||||
|
w.Header()[k] = v
|
||||||
|
}
|
||||||
|
w.Header().Set("GoBlog-Cache", "MISS")
|
||||||
|
w.WriteHeader(code)
|
||||||
|
_, _ = w.Write(recorder.Body.Bytes())
|
||||||
|
// Save cache
|
||||||
|
if code == http.StatusOK {
|
||||||
|
saveCache(path, recorder.Header(), recorder.Body.Bytes())
|
||||||
|
}
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
expiresTime := time.Unix(t+appConfig.cache.expiration, 0).Format(time.RFC1123)
|
expiresTime := time.Unix(cacheTime+appConfig.cache.expiration, 0).Format(time.RFC1123)
|
||||||
|
for k, v := range header {
|
||||||
|
w.Header()[k] = v
|
||||||
|
}
|
||||||
w.Header().Set("Expires", expiresTime)
|
w.Header().Set("Expires", expiresTime)
|
||||||
w.Header().Set("Content-Type", mime)
|
w.Header().Set("GoBlog-Cache", "HIT")
|
||||||
_, _ = w.Write(cache)
|
_, _ = w.Write(body)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
next.ServeHTTP(w, r)
|
next.ServeHTTP(w, r)
|
||||||
|
@ -29,25 +49,26 @@ func CacheMiddleware(next http.Handler) http.Handler {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func getCache(path string, context context.Context) (string, int64, []byte) {
|
func getCache(path string, context context.Context) (creationTime int64, header map[string][]string, body []byte) {
|
||||||
var mime string
|
var headerBytes []byte
|
||||||
var t int64
|
|
||||||
var cache []byte
|
|
||||||
allowedTime := time.Now().Unix() - appConfig.cache.expiration
|
allowedTime := time.Now().Unix() - appConfig.cache.expiration
|
||||||
row := appDb.QueryRowContext(context, "select COALESCE(mime, ''), COALESCE(time, 0), value from cache where path=? and time>=?", path, allowedTime)
|
row := appDb.QueryRowContext(context, "select COALESCE(time, 0), header, body from cache where path=? and time>=?", path, allowedTime)
|
||||||
_ = row.Scan(&mime, &t, &cache)
|
_ = row.Scan(&creationTime, &headerBytes, &body)
|
||||||
return mime, t, cache
|
header = make(map[string][]string)
|
||||||
|
_ = json.Unmarshal(headerBytes, &header)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func saveCache(path string, mime string, value []byte) {
|
func saveCache(path string, header map[string][]string, body []byte) {
|
||||||
now := time.Now().Unix()
|
now := time.Now().Unix()
|
||||||
|
headerBytes, _ := json.Marshal(header)
|
||||||
startWritingToDb()
|
startWritingToDb()
|
||||||
tx, err := appDb.Begin()
|
tx, err := appDb.Begin()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
_, _ = tx.Exec("delete from cache where time<?;", now-appConfig.cache.expiration)
|
_, _ = tx.Exec("delete from cache where time<?;", now-appConfig.cache.expiration)
|
||||||
_, _ = tx.Exec("insert or replace into cache (path, time, mime, value) values (?, ?, ?, ?);", path, now, mime, value)
|
_, _ = tx.Exec("insert or replace into cache (path, time, header, body) values (?, ?, ?, ?);", path, now, headerBytes, body)
|
||||||
_ = tx.Commit()
|
_ = tx.Commit()
|
||||||
finishWritingToDb()
|
finishWritingToDb()
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,7 @@ func migrateDb() error {
|
||||||
&migrator.Migration{
|
&migrator.Migration{
|
||||||
Name: "00004",
|
Name: "00004",
|
||||||
Func: func(tx *sql.Tx) error {
|
Func: func(tx *sql.Tx) error {
|
||||||
_, err := tx.Exec("create table cache (path text not null primary key, time integer, mime text, value blob);")
|
_, err := tx.Exec("create table cache (path text not null primary key, time integer, header blob, body blob);")
|
||||||
return err
|
return err
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
6
posts.go
6
posts.go
|
@ -32,11 +32,7 @@ func servePost(w http.ResponseWriter, r *http.Request) {
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
mime := "text/html"
|
w.Header().Set("Content-Type", "text/html")
|
||||||
if appConfig.cache.enable {
|
|
||||||
saveCache(path, mime, htmlContent)
|
|
||||||
}
|
|
||||||
w.Header().Set("Content-Type", mime)
|
|
||||||
_, _ = w.Write(htmlContent)
|
_, _ = w.Write(htmlContent)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue