feat(cache): 开启缓存默认仅缓存标准静态资源

路由缓存策略新增 static(内置扩展名,不含 HTML)与 all;
存量 url 规范为 all。OpenResty 渲染与代理路由 UI 同步。
This commit is contained in:
ryan
2026-07-18 23:32:49 +08:00
parent 7401f5d0b4
commit 04f029c705
11 changed files with 201 additions and 29 deletions
@@ -278,10 +278,10 @@ export function normalizeLimitRate(value: string) {
}
export function validateCacheRules(
policy: 'url' | 'suffix' | 'path_prefix' | 'path_exact',
policy: 'static' | 'all' | 'url' | 'suffix' | 'path_prefix' | 'path_exact',
rules: string[],
) {
if (policy === 'url') {
if (policy === 'static' || policy === 'all' || policy === 'url') {
return null;
}
@@ -335,7 +335,12 @@ export function buildPayloadFromRoute(
limit_conn_per_ip: route.limit_conn_per_ip,
limit_rate: route.limit_rate,
cache_enabled: route.cache_enabled,
cache_policy: route.cache_policy || 'url',
cache_policy:
!route.cache_policy || route.cache_policy === 'url'
? route.cache_policy === 'url'
? 'all'
: 'static'
: route.cache_policy,
cache_rules: route.cache_rule_list ?? [],
custom_headers: route.custom_header_list ?? [],
basic_auth_enabled: route.basic_auth_enabled,
@@ -229,7 +229,7 @@ export function ProxyRouteCreateSheet({
limit_conn_per_ip: 0,
limit_rate: '',
cache_enabled: false,
cache_policy: 'url',
cache_policy: 'static',
cache_rules: [],
custom_headers: [],
basic_auth_enabled: false,
@@ -36,7 +36,14 @@ import { SectionShell } from './section-shell';
const cacheSchema = z
.object({
cache_enabled: z.boolean(),
cache_policy: z.enum(['url', 'suffix', 'path_prefix', 'path_exact']),
cache_policy: z.enum([
'static',
'all',
'url',
'suffix',
'path_prefix',
'path_exact',
]),
cache_rules_text: z.string(),
})
.superRefine((value, context) => {
@@ -63,6 +70,22 @@ interface CacheSectionProps {
onSavingChange?: (saving: boolean) => void;
}
function normalizeCachePolicyValue(policy: string | undefined | null) {
const value = (policy || '').trim();
if (!value || value === 'static') return 'static';
if (value === 'url' || value === 'all') return 'all';
if (value === 'suffix' || value === 'path_prefix' || value === 'path_exact') {
return value;
}
return 'static';
}
function needsRulesForPolicy(policy: string) {
return (
policy === 'suffix' || policy === 'path_prefix' || policy === 'path_exact'
);
}
export function CacheSection({
route,
onRouteUpdate,
@@ -78,8 +101,9 @@ export function CacheSection({
resolver: zodResolver(cacheSchema),
defaultValues: {
cache_enabled: route.cache_enabled,
cache_policy: (route.cache_policy ||
'url') as CacheValues['cache_policy'],
cache_policy: normalizeCachePolicyValue(
route.cache_policy,
) as CacheValues['cache_policy'],
cache_rules_text: route.cache_rule_list.join('\n'),
},
});
@@ -87,14 +111,19 @@ export function CacheSection({
useEffect(() => {
form.reset({
cache_enabled: route.cache_enabled,
cache_policy: (route.cache_policy ||
'url') as CacheValues['cache_policy'],
cache_policy: normalizeCachePolicyValue(
route.cache_policy,
) as CacheValues['cache_policy'],
cache_rules_text: route.cache_rule_list.join('\n'),
});
}, [form, route]);
const watchedEnabled = form.watch('cache_enabled');
const watchedPolicy = form.watch('cache_policy');
const needsRules =
watchedPolicy === 'suffix' ||
watchedPolicy === 'path_prefix' ||
watchedPolicy === 'path_exact';
const rulesHint =
watchedPolicy === 'suffix'
@@ -103,7 +132,9 @@ export function CacheSection({
? '每行一个路径前缀,例如 /assets、/static。'
: watchedPolicy === 'path_exact'
? '每行一个精确路径,例如 /robots.txt。'
: '按 URL 缓存时无需额外规则。';
: watchedPolicy === 'static'
? '标准静态资源使用内置扩展名列表(不含 HTML),无需填写规则。'
: '所有可缓存 GET 无需额外规则(仍会绕过登录态与 Authorization)。';
const rulesPlaceholder =
watchedPolicy === 'suffix'
@@ -112,7 +143,7 @@ export function CacheSection({
? '/assets\n/static'
: watchedPolicy === 'path_exact'
? '/robots.txt\n/manifest.json'
: '按 URL 缓存时无需额外规则';
: '当前策略无需额外规则';
return (
<SectionShell
@@ -131,10 +162,11 @@ export function CacheSection({
{
cache_enabled: values.cache_enabled,
cache_policy: values.cache_enabled
? values.cache_policy
: 'url',
? normalizeCachePolicyValue(values.cache_policy)
: 'static',
cache_rules:
values.cache_enabled && values.cache_policy !== 'url'
values.cache_enabled &&
needsRulesForPolicy(values.cache_policy)
? rules
: [],
},
@@ -150,8 +182,8 @@ export function CacheSection({
<div className='space-y-0.5'>
<FormLabel>启用站点缓存</FormLabel>
<FormDescription>
系统仍会自动绕过非 GET、带 Authorization 或常见登录态 Cookie
的请求。
开启后默认仅缓存标准静态扩展名(不含 HTML)。仍会自动绕过非
GET、Authorization 与常见登录态 Cookie。
</FormDescription>
</div>
<FormControl>
@@ -181,12 +213,17 @@ export function CacheSection({
</SelectTrigger>
</FormControl>
<SelectContent>
<SelectItem value='url'>按 URL 缓存</SelectItem>
<SelectItem value='suffix'>按后缀缓存</SelectItem>
<SelectItem value='path_prefix'>按路径前缀缓存</SelectItem>
<SelectItem value='path_exact'>按精确路径缓存</SelectItem>
<SelectItem value='static'>标准静态资源(推荐)</SelectItem>
<SelectItem value='all'>所有可缓存 GET(高级)</SelectItem>
<SelectItem value='suffix'>自定义后缀</SelectItem>
<SelectItem value='path_prefix'>路径前缀</SelectItem>
<SelectItem value='path_exact'>精确路径</SelectItem>
</SelectContent>
</Select>
<FormDescription>
标准静态资源含 css/js/图片/字体/媒体等,默认不缓存 HTML
与接口路径。
</FormDescription>
<FormMessage />
</FormItem>
)}
@@ -201,7 +238,7 @@ export function CacheSection({
<FormControl>
<Textarea
className='min-h-32'
disabled={!watchedEnabled || watchedPolicy === 'url'}
disabled={!watchedEnabled || !needsRules}
placeholder={rulesPlaceholder}
{...field}
/>