mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-10-06 15:46:37 +08:00
feat(rate-limit): 站点级请求频率限制支持继承与自定义
在站点详情流量限制中配置 limit_req_per_ip;渲染按 effective rate 生成多 limit_req_zone,并以站点+IP 隔离计数。
This commit is contained in:
@@ -278,6 +278,25 @@ export function normalizeLimitRate(value: string) {
|
||||
return normalized;
|
||||
}
|
||||
|
||||
const limitReqPattern = /^\d+r\/[sm]$/i;
|
||||
|
||||
export function validateLimitReqPerIP(value: string) {
|
||||
const normalized = value.trim();
|
||||
if (!normalized || normalized === '0' || normalized === '-1') {
|
||||
return null;
|
||||
}
|
||||
if (!limitReqPattern.test(normalized)) {
|
||||
return '请求频率格式不合法,请使用 10r/s、100r/m,或 -1 关闭';
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export function normalizeLimitReqPerIP(value: string) {
|
||||
const normalized = value.trim().toLowerCase();
|
||||
if (!normalized || normalized === '0') return '';
|
||||
return normalized;
|
||||
}
|
||||
|
||||
export function validateCacheRules(
|
||||
policy: 'static' | 'all' | 'url' | 'suffix' | 'path_prefix' | 'path_exact',
|
||||
rules: string[],
|
||||
@@ -335,6 +354,7 @@ export function buildPayloadFromRoute(
|
||||
limit_conn_per_server: route.limit_conn_per_server,
|
||||
limit_conn_per_ip: route.limit_conn_per_ip,
|
||||
limit_rate: route.limit_rate,
|
||||
limit_req_per_ip: route.limit_req_per_ip,
|
||||
cache_enabled: route.cache_enabled,
|
||||
cache_policy: (() => {
|
||||
if (!route.cache_enabled) {
|
||||
|
||||
@@ -228,6 +228,7 @@ export function ProxyRouteCreateSheet({
|
||||
limit_conn_per_server: 0,
|
||||
limit_conn_per_ip: 0,
|
||||
limit_rate: '',
|
||||
limit_req_per_ip: '',
|
||||
cache_enabled: true,
|
||||
cache_policy: 'static',
|
||||
cache_rules: [],
|
||||
|
||||
@@ -19,7 +19,9 @@ import type { ProxyRouteItem } from '@/lib/services/openflare';
|
||||
|
||||
import {
|
||||
normalizeLimitRate,
|
||||
normalizeLimitReqPerIP,
|
||||
validateLimitRate,
|
||||
validateLimitReqPerIP,
|
||||
} from '../../components/helpers';
|
||||
import { proxyRouteFormIds } from '../helpers';
|
||||
import { useRouteSectionSave } from '../hooks/use-route-section-save';
|
||||
@@ -30,6 +32,7 @@ const rateLimitSchema = z
|
||||
limit_conn_per_server: z.string(),
|
||||
limit_conn_per_ip: z.string(),
|
||||
limit_rate: z.string(),
|
||||
limit_req_per_ip: z.string(),
|
||||
})
|
||||
.superRefine((value, context) => {
|
||||
for (const field of [
|
||||
@@ -57,6 +60,15 @@ const rateLimitSchema = z
|
||||
message: limitRateError,
|
||||
});
|
||||
}
|
||||
|
||||
const limitReqError = validateLimitReqPerIP(value.limit_req_per_ip);
|
||||
if (limitReqError) {
|
||||
context.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
path: ['limit_req_per_ip'],
|
||||
message: limitReqError,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
type RateLimitValues = z.infer<typeof rateLimitSchema>;
|
||||
@@ -99,6 +111,7 @@ export function LimitsSection({
|
||||
limit_conn_per_server: formatConnValue(route.limit_conn_per_server),
|
||||
limit_conn_per_ip: formatConnValue(route.limit_conn_per_ip),
|
||||
limit_rate: route.limit_rate || '',
|
||||
limit_req_per_ip: route.limit_req_per_ip || '',
|
||||
},
|
||||
});
|
||||
|
||||
@@ -107,6 +120,7 @@ export function LimitsSection({
|
||||
limit_conn_per_server: formatConnValue(route.limit_conn_per_server),
|
||||
limit_conn_per_ip: formatConnValue(route.limit_conn_per_ip),
|
||||
limit_rate: route.limit_rate || '',
|
||||
limit_req_per_ip: route.limit_req_per_ip || '',
|
||||
});
|
||||
}, [form, route]);
|
||||
|
||||
@@ -129,6 +143,9 @@ export function LimitsSection({
|
||||
),
|
||||
limit_conn_per_ip: parseConnValue(values.limit_conn_per_ip),
|
||||
limit_rate: normalizeLimitRate(values.limit_rate),
|
||||
limit_req_per_ip: normalizeLimitReqPerIP(
|
||||
values.limit_req_per_ip,
|
||||
),
|
||||
},
|
||||
'流量限制已保存',
|
||||
);
|
||||
@@ -172,7 +189,7 @@ export function LimitsSection({
|
||||
control={form.control}
|
||||
name='limit_rate'
|
||||
render={({ field }) => (
|
||||
<FormItem className='md:col-span-2'>
|
||||
<FormItem>
|
||||
<FormLabel>限速</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder='512k/1m 或 -1' {...field} />
|
||||
@@ -184,6 +201,24 @@ export function LimitsSection({
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name='limit_req_per_ip'
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>单 IP 请求频率</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder='10r/s / 100r/m 或 -1' {...field} />
|
||||
</FormControl>
|
||||
<FormDescription>
|
||||
空或 0 继承全局默认;-1 关闭;例如 10r/s、100r/m
|
||||
为自定义频率。
|
||||
</FormDescription>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</form>
|
||||
</Form>
|
||||
</SectionShell>
|
||||
|
||||
@@ -233,6 +233,7 @@ export interface ProxyRouteItem {
|
||||
limit_conn_per_server: number;
|
||||
limit_conn_per_ip: number;
|
||||
limit_rate: string;
|
||||
limit_req_per_ip: string;
|
||||
cache_enabled: boolean;
|
||||
cache_policy: string;
|
||||
cache_rules: string;
|
||||
@@ -269,6 +270,7 @@ export interface ProxyRouteMutationPayload {
|
||||
limit_conn_per_server?: number;
|
||||
limit_conn_per_ip?: number;
|
||||
limit_rate?: string;
|
||||
limit_req_per_ip?: string;
|
||||
cache_enabled: boolean;
|
||||
cache_policy: string;
|
||||
cache_rules: string[];
|
||||
|
||||
Reference in New Issue
Block a user