feat: Reverse proxy supports configuring server caching (#9914)

This commit is contained in:
CityFun 2025-08-08 16:59:49 +08:00 committed by GitHub
parent c2ad006a19
commit 2b7ec9ffe1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 141 additions and 41 deletions

View file

@ -203,22 +203,24 @@ type WebsiteUpdateDirPermission struct {
}
type WebsiteProxyConfig struct {
ID uint `json:"id" validate:"required"`
Operate string `json:"operate" validate:"required"`
Enable bool `json:"enable" `
Cache bool `json:"cache" `
CacheTime int `json:"cacheTime" `
CacheUnit string `json:"cacheUnit"`
Name string `json:"name" validate:"required"`
Modifier string `json:"modifier"`
Match string `json:"match" validate:"required"`
ProxyPass string `json:"proxyPass" validate:"required"`
ProxyHost string `json:"proxyHost" validate:"required"`
Content string `json:"content"`
FilePath string `json:"filePath"`
Replaces map[string]string `json:"replaces"`
SNI bool `json:"sni"`
ProxySSLName string `json:"proxySSLName"`
ID uint `json:"id" validate:"required"`
Operate string `json:"operate" validate:"required"`
Enable bool `json:"enable" `
Cache bool `json:"cache" `
CacheTime int `json:"cacheTime"`
CacheUnit string `json:"cacheUnit"`
ServerCacheTime int `json:"serverCacheTime"`
ServerCacheUnit string `json:"serverCacheUnit"`
Name string `json:"name" validate:"required"`
Modifier string `json:"modifier"`
Match string `json:"match" validate:"required"`
ProxyPass string `json:"proxyPass" validate:"required"`
ProxyHost string `json:"proxyHost" validate:"required"`
Content string `json:"content"`
FilePath string `json:"filePath"`
Replaces map[string]string `json:"replaces"`
SNI bool `json:"sni"`
ProxySSLName string `json:"proxySSLName"`
}
type WebsiteProxyReq struct {

View file

@ -1651,7 +1651,7 @@ func (w WebsiteService) OperateProxy(req request.WebsiteProxyConfig) (err error)
if err = openProxyCache(website); err != nil {
return
}
location.AddCache(req.CacheTime, req.CacheUnit, fmt.Sprintf("proxy_cache_zone_of_%s", website.Alias))
location.AddCache(req.CacheTime, req.CacheUnit, fmt.Sprintf("proxy_cache_zone_of_%s", website.Alias), req.ServerCacheTime, req.ServerCacheUnit)
} else {
location.RemoveCache(fmt.Sprintf("proxy_cache_zone_of_%s", website.Alias))
}
@ -1811,6 +1811,10 @@ func (w WebsiteService) GetProxies(id uint) (res []request.WebsiteProxyConfig, e
proxyConfig.CacheTime = location.CacheTime
proxyConfig.CacheUnit = location.CacheUint
}
if location.ServerCacheTime > 0 {
proxyConfig.ServerCacheTime = location.ServerCacheTime
proxyConfig.ServerCacheUnit = location.ServerCacheUint
}
proxyConfig.Match = location.Match
proxyConfig.Modifier = location.Modifier
proxyConfig.ProxyHost = location.Host

View file

@ -8,18 +8,20 @@ import (
)
type Location struct {
Modifier string
Match string
Cache bool
ProxyPass string
Host string
CacheTime int
CacheUint string
Comment string
Directives []IDirective
Line int
Parameters []string
Replaces map[string]string
Modifier string
Match string
Cache bool
ProxyPass string
Host string
CacheTime int
CacheUint string
Comment string
Directives []IDirective
Line int
Parameters []string
Replaces map[string]string
ServerCacheTime int
ServerCacheUint string
}
func (l *Location) GetCodeBlock() string {
@ -67,6 +69,22 @@ func NewLocation(directive IDirective) *Location {
}
}
}
case "proxy_cache_valid":
timeParam := params[len(params)-1]
re := regexp.MustCompile(`^(\d+)(\w+)$`)
matches := re.FindStringSubmatch(timeParam)
if matches == nil {
continue
}
cacheTime, err := strconv.Atoi(matches[1])
if err != nil {
continue
}
unit := matches[2]
location.ServerCacheTime = cacheTime
location.ServerCacheUint = unit
case "sub_filter":
if location.Replaces == nil {
location.Replaces = make(map[string]string, 0)
@ -186,13 +204,14 @@ func (l *Location) ChangePath(Modifier string, Match string) {
l.Match = Match
}
func (l *Location) AddCache(cacheTime int, cacheUint, cacheKey string) {
func (l *Location) AddCache(cacheTime int, cacheUint, cacheKey string, serverCacheTime int, serverCacheUint string) {
l.RemoveDirective("add_header", []string{"Cache-Control", "no-cache"})
l.RemoveDirective("if", []string{"(", "$uri", "~*", `"\.(gif|png|jpg|css|js|woff|woff2)$"`, ")"})
l.RemoveDirective("if", []string{"(", "$uri", "~*", `"\.(gif|png|jpg|css|js|woff|woff2|jpeg|svg|webp|avif)$"`, ")"})
directives := l.GetDirectives()
newDir := &Directive{
Name: "if",
Parameters: []string{"(", "$uri", "~*", `"\.(gif|png|jpg|css|js|woff|woff2)$"`, ")"},
Parameters: []string{"(", "$uri", "~*", `"\.(gif|png|jpg|css|js|woff|woff2|jpeg|svg|webp|avif)$"`, ")"},
Block: &Block{},
}
block := &Block{}
@ -206,7 +225,7 @@ func (l *Location) AddCache(cacheTime int, cacheUint, cacheKey string) {
l.UpdateDirective("proxy_ignore_headers", []string{"Set-Cookie", "Cache-Control", "expires"})
l.UpdateDirective("proxy_cache", []string{cacheKey})
l.UpdateDirective("proxy_cache_key", []string{"$host$uri$is_args$args"})
l.UpdateDirective("proxy_cache_valid", []string{"200", "304", "301", "302", "10m"})
l.UpdateDirective("proxy_cache_valid", []string{"200", "304", "301", "302", strconv.Itoa(serverCacheTime) + serverCacheUint})
l.Cache = true
l.CacheTime = cacheTime
l.CacheUint = cacheUint
@ -214,6 +233,7 @@ func (l *Location) AddCache(cacheTime int, cacheUint, cacheKey string) {
func (l *Location) RemoveCache(cacheKey string) {
l.RemoveDirective("if", []string{"(", "$uri", "~*", `"\.(gif|png|jpg|css|js|woff|woff2)$"`, ")"})
l.RemoveDirective("if", []string{"(", "$uri", "~*", `"\.(gif|png|jpg|css|js|woff|woff2|jpeg|svg|webp|avif)$"`, ")"})
l.RemoveDirective("proxy_ignore_headers", []string{"Set-Cookie"})
l.RemoveDirective("proxy_cache", []string{cacheKey})
l.RemoveDirective("proxy_cache_key", []string{"$host$uri$is_args$args"})

View file

@ -388,6 +388,8 @@ export namespace Website {
cache: boolean;
cacheTime: number;
cacheUnit: string;
serverCacheTime: number;
serverCacheUnit: string;
name: string;
modifier: string;
match: string;

View file

@ -2505,6 +2505,12 @@ const message = {
openBaseDir: 'Prevent Cross-Site Attacks',
openBaseDirHelper:
'open_basedir is used to restrict the PHP file access path, which helps prevent cross-site access and enhance security',
serverCacheTime: 'Server Cache Time',
serverCacheTimeHelper:
'The time a request is cached on the server. During this period, identical requests will return the cached result directly without requesting the origin server.',
browserCacheTime: 'Browser Cache Time',
browserCacheTimeHelper:
'The time static resources are cached locally in the browser, reducing redundant requests. Users will use the local cache directly before it expires when refreshing the page.',
},
php: {
short_open_tag: 'Short tag support',

View file

@ -2421,6 +2421,12 @@ const message = {
openBaseDir: 'クロスサイト攻撃を防ぐ',
openBaseDirHelper:
'open_basedir PHP ファイルのアクセスパスを制限しクロスサイトアクセスを防ぎセキュリティを向上させるために使用されます',
serverCacheTime: 'サーバーキャッシュ時間',
serverCacheTimeHelper:
'リクエストがサーバー上でキャッシュされる時間この期間中同一のリクエストはオリジンサーバーにリクエストせずキャッシュされた結果を直接返します',
browserCacheTime: 'ブラウザキャッシュ時間',
browserCacheTimeHelper:
'静的リソースがブラウザのローカルにキャッシュされる時間冗長なリクエストを減らします有効期限前にユーザーがページをリフレッシュするとローカルキャッシュが直接使用されます',
},
php: {
short_open_tag: '短いタグサポート',

View file

@ -2379,6 +2379,12 @@ const message = {
openBaseDir: '사이트 공격 방지',
openBaseDirHelper:
'open_basedir는 PHP 파일 액세스 경로를 제한하여 사이트 액세스를 방지하고 보안을 향상시키는 사용됩니다',
serverCacheTime: '서버 캐시 시간',
serverCacheTimeHelper:
'요청이 서버에서 캐시되는 시간. 기간 동안 동일한 요청은 원본 서버에 요청하지 않고 캐시된 결과를 직접 반환합니다.',
browserCacheTime: '브라우저 캐시 시간',
browserCacheTimeHelper:
'정적 리소스가 브라우저 로컬에 캐시되는 시간, 중복 요청을 줄입니다. 유효기간 전에 사용자가 페이지를 새로 고치면 로컬 캐시가 직접 사용됩니다.',
},
php: {
short_open_tag: '짧은 태그 지원',

View file

@ -2476,6 +2476,12 @@ const message = {
openBaseDir: 'Pencegahan Serangan Lintas Situs',
openBaseDirHelper:
'open_basedir digunakan untuk membatasi jalur akses file PHP, yang membantu mencegah akses lintas situs dan meningkatkan keamanan',
serverCacheTime: 'Masa Cache Pelayan',
serverCacheTimeHelper:
'Masa permintaan di-cache di pelayan. Semasa tempoh ini, permintaan yang sama akan mengembalikan hasil cache terus tanpa meminta pelayan asal.',
browserCacheTime: 'Masa Cache Pelayar',
browserCacheTimeHelper:
'Masa sumber statik di-cache secara tempatan di pelayar, mengurangkan permintaan berulang. Pengguna akan menggunakan cache tempatan secara langsung sebelum tamat tempoh semasa menyegarkan halaman.',
},
php: {
short_open_tag: 'Sokongan tag pendek',

View file

@ -2477,6 +2477,12 @@ const message = {
openBaseDir: 'Prevenir Ataques entre Sites',
openBaseDirHelper:
'open_basedir é usado para restringir o caminho de acesso a arquivos PHP, ajudando a prevenir acesso entre sites e aumentar a segurança',
serverCacheTime: 'Tempo de Cache do Servidor',
serverCacheTimeHelper:
'O tempo que uma requisição é armazenada em cache no servidor. Durante este período, requisições idênticas retornarão o resultado em cache diretamente, sem pedir ao servidor de origem.',
browserCacheTime: 'Tempo de Cache do Navegador',
browserCacheTimeHelper:
'O tempo que os recursos estáticos são armazenados em cache localmente no navegador, reduzindo requisições redundantes. Os usuários usarão o cache local diretamente antes de expirar ao atualizar a página.',
},
php: {
short_open_tag: 'Suporte para short tags',

View file

@ -2474,6 +2474,12 @@ const message = {
openBaseDir: 'Предотвращение межсайтовых атак',
openBaseDirHelper:
'open_basedir используется для ограничения пути доступа к файлам PHP, что помогает предотвратить межсайтовый доступ и повысить безопасность',
serverCacheTime: 'Время кеширования на сервере',
serverCacheTimeHelper:
'Время, в течение которого запрос кешируется на сервере. В этот период идентичные запросы будут возвращать кешированный результат напрямую, без запроса к исходному серверу.',
browserCacheTime: 'Время кеширования в браузере',
browserCacheTimeHelper:
'Время, в течение которого статические ресурсы кешируются локально в браузере, уменьшая повторные запросы. Пользователи будут использовать локальный кеш напрямую, если срок его действия не истек при обновлении страницы.',
},
php: {
short_open_tag: 'Поддержка коротких тегов',

View file

@ -2536,6 +2536,12 @@ const message = {
openBaseDir: 'Siteler Arası Saldırıları Önle',
openBaseDirHelper:
'open_basedir, PHP dosya erişim yolunu kısıtlamak için kullanılır, bu siteler arası erişimi önlemeye ve güvenliği artırmaya yardımcı olur',
serverCacheTime: 'Sunucu Önbellek Süresi',
serverCacheTimeHelper:
'Bir isteğin sunucuda önbelleğe alındığı süre. Bu süre boyunca, aynı istekler önbelleğe alınmış sonucu doğrudan döndürür ve kaynak sunucuya istekte bulunmaz.',
browserCacheTime: 'Tarayıcı Önbellek Süresi',
browserCacheTimeHelper:
'Statik kaynakların tarayıcıda yerel olarak önbelleğe alındığı süre, tekrarlayan istekleri azaltır. Kullanıcılar süre dolmadan önce sayfayı yenilediğinde yerel önbelleği doğrudan kullanır.',
},
php: {
short_open_tag: 'Kısa etiket desteği',

View file

@ -2339,6 +2339,10 @@ const message = {
westCN: '西部數碼',
openBaseDir: '防跨站攻擊',
openBaseDirHelper: 'open_basedir 用於限制 PHP 文件訪問路徑有助於防止跨站訪問和提升安全性',
serverCacheTime: '伺服器緩存時間',
serverCacheTimeHelper: '請求在伺服器端緩存的時間到期前相同請求會直接返回緩存結果不再請求源站',
browserCacheTime: '瀏覽器緩存時間',
browserCacheTimeHelper: '靜態資源在瀏覽器本地緩存的時間減少重複請求到期前用戶刷新頁面會直接使用本地緩存',
},
php: {
short_open_tag: '短標簽支持',

View file

@ -2328,6 +2328,10 @@ const message = {
westCN: '西部数码',
openBaseDir: '防跨站攻击',
openBaseDirHelper: 'open_basedir 用于限制 PHP 文件访问路径有助于防止跨站访问和提升安全性',
serverCacheTime: '服务器缓存时间',
serverCacheTimeHelper: '请求在服务器端缓存的时间到期前相同请求会直接返回缓存结果不再请求源站',
browserCacheTime: '浏览器缓存时间',
browserCacheTimeHelper: '静态资源在浏览器本地缓存的时间减少重复请求到期前用户刷新页面会直接使用本地缓存',
},
php: {
short_open_tag: '短标签支持',

View file

@ -16,17 +16,10 @@
<el-form-item :label="$t('website.enableCache')" prop="cache">
<el-switch v-model="proxy.cache" @change="changeCache(proxy.cache)"></el-switch>
</el-form-item>
<el-form-item :label="$t('website.sni')" prop="sni">
<el-switch v-model="proxy.sni"></el-switch>
<span class="input-help">{{ $t('website.sniHelper') }}</span>
</el-form-item>
<el-form-item label="proxy_ssl_name" prop="proxySSLName" v-if="proxy.sni">
<el-input v-model.trim="proxy.proxySSLName"></el-input>
</el-form-item>
<el-form-item :label="$t('website.cacheTime')" prop="cacheTime" v-if="proxy.cache">
<el-form-item :label="$t('website.browserCacheTime')" prop="cacheTime" v-if="proxy.cache">
<el-input v-model.number="proxy.cacheTime" maxlength="15">
<template #append>
<el-select v-model="proxy.cacheUnit" style="width: 100px">
<el-select v-model="proxy.cacheUnit" class="p-w-100">
<el-option
v-for="(unit, index) in Units"
:key="index"
@ -36,6 +29,29 @@
</el-select>
</template>
</el-input>
<span class="input-help">{{ $t('website.browserCacheTimeHelper') }}</span>
</el-form-item>
<el-form-item :label="$t('website.serverCacheTime')" prop="cacheTime" v-if="proxy.cache">
<el-input v-model.number="proxy.serverCacheTime" maxlength="15">
<template #append>
<el-select v-model="proxy.serverCacheUnit" class="p-w-100">
<el-option
v-for="(unit, index) in Units"
:key="index"
:label="unit.label"
:value="unit.value"
></el-option>
</el-select>
</template>
</el-input>
<span class="input-help">{{ $t('website.serverCacheTimeHelper') }}</span>
</el-form-item>
<el-form-item :label="$t('website.sni')" prop="sni">
<el-switch v-model="proxy.sni"></el-switch>
<span class="input-help">{{ $t('website.sniHelper') }}</span>
</el-form-item>
<el-form-item label="proxy_ssl_name" prop="proxySSLName" v-if="proxy.sni">
<el-input v-model.trim="proxy.proxySSLName"></el-input>
</el-form-item>
<el-row :gutter="10">
<el-col :span="12">
@ -140,6 +156,8 @@ const initData = (): Website.ProxyConfig => ({
proxyProtocol: 'http://',
sni: false,
proxySSLName: '',
serverCacheTime: 10,
serverCacheUnit: 'm',
});
let proxy = ref(initData());
const replaces = ref<any>([]);
@ -174,9 +192,13 @@ const changeCache = (cache: boolean) => {
if (cache) {
proxy.value.cacheTime = 1;
proxy.value.cacheUnit = 'm';
proxy.value.serverCacheTime = 10;
proxy.value.serverCacheUnit = 'm';
} else {
proxy.value.cacheTime = 0;
proxy.value.cacheUnit = '';
proxy.value.serverCacheTime = 0;
proxy.value.serverCacheUnit = '';
}
};