Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add response-cache plugin #2025

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

mirror58229
Copy link
Contributor

Ⅰ. Describe what this PR did

Enable caching responses for Higress. This feature supports extracting keys from request headers or request bodies, and caching values extracted from response bodies. If the response is in JSON format, it supports GJSON PATH.

This function is similar to ai-cache, but it focuses more on common scenarios, such as caching HTTP responses or other static results.

Ⅱ. Does this pull request fix one issue?

Ⅲ. Why don't you add test cases (unit test/integration test)?

Ⅳ. Describe how to verify it

Ⅴ. Special notes for reviews

@codecov-commenter
Copy link

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 43.72%. Comparing base (ef31e09) to head (1861889).
Report is 424 commits behind head on main.

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #2025      +/-   ##
==========================================
+ Coverage   35.91%   43.72%   +7.81%     
==========================================
  Files          69       79      +10     
  Lines       11576    12728    +1152     
==========================================
+ Hits         4157     5565    +1408     
+ Misses       7104     6816     -288     
- Partials      315      347      +32     

see 75 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Collaborator

@CH3CHO CH3CHO left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

先看了一下文档,逻辑还没看。

**Note**

> 需要数据面的proxy wasm版本大于等于0.2.100
> 编译时,需要带上版本的tag,例如:`tinygo build -o main.wasm -scheduler=none -target=wasi -gc=custom -tags="custommalloc nottinygc_finalizer proxy_wasm_version_0_2_100" ./`
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

需要加这个tag的话,请参考ai-proxy等插件添加.buildrc文件。

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

如果不需要再 onRequestBody 阶段修改 header,可以不需要加这个 tag。

| --- | --- | --- | --- | --- |
| cacheResponseCode | array of number | optional | 200 | 表示支持缓存的响应状态码列表;默认为200|
| cacheKeyFromHeader | string | required | "" | 表示提取header中的固定字段的值作为缓存key;cacheKeyFromHeader和cacheKeyFromBody**非空情况下只支持配置一项**|
| cacheKeyFromBody | string | required | "" | 配置为空时,表示提取所有body作为缓存key;否则按json响应格式,从请求 Body 中基于 [GJSON PATH](https://github.com/tidwall/gjson/blob/master/SYNTAX.md) 语法提取字符串 |
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

那如果cacheKey完全不看body要怎么配呢?

| cacheResponseCode | array of number | optional | 200 | 表示支持缓存的响应状态码列表;默认为200|
| cacheKeyFromHeader | string | required | "" | 表示提取header中的固定字段的值作为缓存key;cacheKeyFromHeader和cacheKeyFromBody**非空情况下只支持配置一项**|
| cacheKeyFromBody | string | required | "" | 配置为空时,表示提取所有body作为缓存key;否则按json响应格式,从请求 Body 中基于 [GJSON PATH](https://github.com/tidwall/gjson/blob/master/SYNTAX.md) 语法提取字符串 |
| cacheValueFromBodyType | string | optional | "application/json" | 表示缓存body的类型,命中cache时content-type会返回该值;默认为json |
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个感觉有点奇怪,为什么不是返回缓存数据的content type呢?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

默认为json

这里要写也得写完整的。


其中,缓存key的拼接逻辑为以下中一个:
1. `cacheKeyPrefix` + 从请求头中`cacheKeyFromHeader`对应字段提取的内容
2. `cacheKeyPrefix` + 从请求体中`cacheKeyFromBody`对应字段提取的内容
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

两个都不为空呢?


## 常见问题

1. 如果返回的错误为 `error status returned by host: bad argument`,请检查`serviceName`是否正确包含了服务的类型后缀(.dns等)。
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

端口也要注意的,尤其是 static 类型的服务端口现在固定为 80。

| cacheKeyFromHeader | string | required | "" | 表示提取header中的固定字段的值作为缓存key;cacheKeyFromHeader和cacheKeyFromBody**非空情况下只支持配置一项**|
| cacheKeyFromBody | string | required | "" | 配置为空时,表示提取所有body作为缓存key;否则按json响应格式,从请求 Body 中基于 [GJSON PATH](https://github.com/tidwall/gjson/blob/master/SYNTAX.md) 语法提取字符串 |
| cacheValueFromBodyType | string | optional | "application/json" | 表示缓存body的类型,命中cache时content-type会返回该值;默认为json |
| cacheValueFromBody | string | optional | "" | 配置为空时,表示缓存所有body;当cacheValueFromBodyType为json时,支持从响应 Body 中基于 [GJSON PATH](https://github.com/tidwall/gjson/blob/master/SYNTAX.md) 语法提取字符串 |
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

不太能理解什么场景下需要这个功能。

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

当cacheValueFromBodyType为json时

这里要写完整的 application/json

}

if len(c.CacheResponseCode) == 0 {
c.CacheResponseCode = []int32{200}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

行尾空格请删除

Comment on lines +28 to +32
wrapper.ParseConfigBy(parseConfig),
wrapper.ProcessRequestHeadersBy(onHttpRequestHeaders),
wrapper.ProcessRequestBodyBy(onHttpRequestBody),
wrapper.ProcessResponseHeadersBy(onHttpResponseHeaders),
wrapper.ProcessResponseBodyBy(onHttpResponseBody),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

作为新插件,这些 deprecated 的写法可以更新了。具体可以参考 ai-proxy 插件的代码。

image


// cache from request header
if c.CacheKeyFromHeader != "" {
key, _ := proxywasm.GetHttpRequestHeader((c.CacheKeyFromHeader))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

多了一层括号

if key == "" {
log.Warnf("[onHttpRequestHeaders] cache key from header: %s is empty, skip cache", c.CacheKeyFromHeader)
ctx.DontReadRequestBody()
return types.ActionContinue
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里是不是也需要跳过 response 的处理流程?感觉现在的处理有点问题。

}

// handleInternalError logs an error and resumes the HTTP request.
func handleInternalError(err error, message string, log wrapper.Log) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这个函数好像没用到?

}

func onHttpResponseBody(ctx wrapper.HttpContext, c config.PluginConfig, body []byte, log wrapper.Log) types.Action {

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

多余空行

| cacheResponseCode | array of number | optional | 200 | 表示支持缓存的响应状态码列表;默认为200|
| cacheKeyFromHeader | string | required | "" | 表示提取header中的固定字段的值作为缓存key;cacheKeyFromHeader和cacheKeyFromBody**非空情况下只支持配置一项**|
| cacheKeyFromBody | string | required | "" | 配置为空时,表示提取所有body作为缓存key;否则按json响应格式,从请求 Body 中基于 [GJSON PATH](https://github.com/tidwall/gjson/blob/master/SYNTAX.md) 语法提取字符串 |
| cacheValueFromBodyType | string | optional | "application/json" | 表示缓存body的类型,命中cache时content-type会返回该值;默认为json |
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

默认为json

这里要写也得写完整的。

| cacheKeyFromHeader | string | required | "" | 表示提取header中的固定字段的值作为缓存key;cacheKeyFromHeader和cacheKeyFromBody**非空情况下只支持配置一项**|
| cacheKeyFromBody | string | required | "" | 配置为空时,表示提取所有body作为缓存key;否则按json响应格式,从请求 Body 中基于 [GJSON PATH](https://github.com/tidwall/gjson/blob/master/SYNTAX.md) 语法提取字符串 |
| cacheValueFromBodyType | string | optional | "application/json" | 表示缓存body的类型,命中cache时content-type会返回该值;默认为json |
| cacheValueFromBody | string | optional | "" | 配置为空时,表示缓存所有body;当cacheValueFromBodyType为json时,支持从响应 Body 中基于 [GJSON PATH](https://github.com/tidwall/gjson/blob/master/SYNTAX.md) 语法提取字符串 |
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

当cacheValueFromBodyType为json时

这里要写完整的 application/json

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants