Cache middleware now records the response and writes that to the DB

This commit is contained in:
Jan-Lukas Else 2020-07-30 16:43:04 +02:00
parent 2639cd9f3b
commit 65ce24d410
3 changed files with 38 additions and 21 deletions

View File

@ -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()
} }

View File

@ -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
}, },
}, },

View File

@ -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)
} }