mirror of
https://github.com/alibaba/higress.git
synced 2026-03-15 22:30:47 +08:00
feat: Add response-cache plugin (#3061)
Co-authored-by: mirror58229 <674958229@qq.com>
This commit is contained in:
100
plugins/wasm-go/extensions/response-cache/core.go
Normal file
100
plugins/wasm-go/extensions/response-cache/core.go
Normal file
@@ -0,0 +1,100 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/alibaba/higress/plugins/wasm-go/extensions/response-cache/cache"
|
||||
"github.com/alibaba/higress/plugins/wasm-go/extensions/response-cache/config"
|
||||
"github.com/higress-group/proxy-wasm-go-sdk/proxywasm"
|
||||
"github.com/higress-group/wasm-go/pkg/log"
|
||||
"github.com/higress-group/wasm-go/pkg/wrapper"
|
||||
"github.com/tidwall/resp"
|
||||
)
|
||||
|
||||
// buildCacheKey constructs the full cache key by combining the prefix with the actual key.
|
||||
func buildCacheKey(provider cache.Provider, key string) string {
|
||||
return provider.GetCacheKeyPrefix() + key
|
||||
}
|
||||
|
||||
// CheckCacheForKey checks if the key is in the cache, or triggers similarity search if not found.
|
||||
func CheckCacheForKey(key string, ctx wrapper.HttpContext, c config.PluginConfig) error {
|
||||
activeCacheProvider := c.GetCacheProvider()
|
||||
if activeCacheProvider == nil {
|
||||
return logAndReturnError("[CheckCacheForKey] no cache provider configured")
|
||||
}
|
||||
|
||||
queryKey := buildCacheKey(activeCacheProvider, key)
|
||||
log.Debugf("[%s] [CheckCacheForKey] querying cache with key: %s", PLUGIN_NAME, queryKey)
|
||||
|
||||
err := activeCacheProvider.Get(queryKey, func(response resp.Value) {
|
||||
handleCacheResponse(key, response, ctx, c)
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
log.Errorf("[%s] [CheckCacheForKey] failed to retrieve key: %s from cache, error: %v", PLUGIN_NAME, key, err)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// handleCacheResponse processes cache response and handles cache hits and misses.
|
||||
func handleCacheResponse(key string, response resp.Value, ctx wrapper.HttpContext, c config.PluginConfig) {
|
||||
if err := response.Error(); err == nil && !response.IsNull() {
|
||||
log.Infof("[%s] cache hit for key: %s", PLUGIN_NAME, key)
|
||||
processCacheHit(key, response.String(), ctx, c)
|
||||
return
|
||||
}
|
||||
|
||||
log.Infof("[%s] [handleCacheResponse] cache miss for key: %s", PLUGIN_NAME, key)
|
||||
if err := response.Error(); err != nil {
|
||||
log.Errorf("[%s] [handleCacheResponse] error retrieving key: %s from cache, error: %v", PLUGIN_NAME, key, err)
|
||||
}
|
||||
proxywasm.ResumeHttpRequest()
|
||||
}
|
||||
|
||||
// processCacheHit handles a successful cache hit.
|
||||
func processCacheHit(key string, response string, ctx wrapper.HttpContext, c config.PluginConfig) {
|
||||
if strings.TrimSpace(response) == "" {
|
||||
log.Warnf("[%s] [processCacheHit] cached response for key %s is empty", PLUGIN_NAME, key)
|
||||
proxywasm.ResumeHttpRequest()
|
||||
return
|
||||
}
|
||||
|
||||
log.Debugf("[%s] [processCacheHit] cached response for key %s: %s", PLUGIN_NAME, key, response)
|
||||
|
||||
ctx.SetContext(CACHE_KEY_CONTEXT_KEY, nil)
|
||||
|
||||
contentType := c.CacheValueFromBodyType
|
||||
headers := [][2]string{
|
||||
{"content-type", contentType},
|
||||
{"x-cache-status", "hit"},
|
||||
}
|
||||
|
||||
proxywasm.SendHttpResponseWithDetail(200, "response-cache.hit", headers, []byte(response), -1)
|
||||
|
||||
}
|
||||
|
||||
// logAndReturnError logs an error and returns it.
|
||||
func logAndReturnError(message string) error {
|
||||
message = fmt.Sprintf("[%s] %s", PLUGIN_NAME, message)
|
||||
log.Errorf(message)
|
||||
return errors.New(message)
|
||||
}
|
||||
|
||||
// Caches the response value
|
||||
func cacheResponse(ctx wrapper.HttpContext, c config.PluginConfig, key string, value string) {
|
||||
if strings.TrimSpace(value) == "" {
|
||||
log.Warnf("[%s] [cacheResponse] cached value for key %s is empty", PLUGIN_NAME, key)
|
||||
return
|
||||
}
|
||||
|
||||
activeCacheProvider := c.GetCacheProvider()
|
||||
if activeCacheProvider != nil {
|
||||
queryKey := buildCacheKey(activeCacheProvider, key)
|
||||
_ = activeCacheProvider.Set(queryKey, value, nil)
|
||||
log.Debugf("[%s] [cacheResponse] cache set success, key: %s, length of value: %d", PLUGIN_NAME, queryKey, len(value))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user