diff --git a/src/pages/Route/Create.tsx b/src/pages/Route/Create.tsx index 326f6675908629..51ee1c042b8107 100644 --- a/src/pages/Route/Create.tsx +++ b/src/pages/Route/Create.tsx @@ -156,7 +156,9 @@ const Page: React.FC = (props) => { ...form2.getFieldsValue(), ...data, }); + setStep2Data({ ...form2.getFieldsValue(), ...params } as RouteModule.Step2Data); }); + return; } setStep2Data({ ...form2.getFieldsValue(), ...params } as RouteModule.Step2Data); }} diff --git a/src/pages/Route/components/Step2/RequestRewriteView.tsx b/src/pages/Route/components/Step2/RequestRewriteView.tsx index 8bb4616feb8e44..da56ef1004e700 100644 --- a/src/pages/Route/components/Step2/RequestRewriteView.tsx +++ b/src/pages/Route/components/Step2/RequestRewriteView.tsx @@ -21,7 +21,12 @@ import { Input, Row, Col, InputNumber, Button, Select } from 'antd'; import { PlusOutlined, MinusCircleOutlined } from '@ant-design/icons'; import { useIntl } from 'umi'; -import { FORM_ITEM_LAYOUT, FORM_ITEM_WITHOUT_LABEL } from '@/pages/Route/constants'; +import { + FORM_ITEM_LAYOUT, + FORM_ITEM_WITHOUT_LABEL, + HASH_KEY_LIST, + HASH_ON_LIST, +} from '@/pages/Route/constants'; import PanelSection from '@/components/PanelSection'; import styles from '../../Create.less'; import { fetchUpstreamList } from '../../service'; @@ -48,117 +53,157 @@ const RequestRewriteView: React.FC = ({ data, form, disabled, onChange }) }); }, []); const renderUpstreamMeta = () => ( - - {(fields, { add, remove }) => ( + <> + + + + {step2Data.type === 'chash' && ( <> - {fields.map((field, index) => ( - - - - - - - - - - - - - - - - - - - {!upstreamDisabled && - (fields.length > 1 ? ( - { - remove(field.name); - }} - /> - ) : null)} - - - - ))} - {!upstreamDisabled && ( - - - - )} + + + + + + )} - + + {(fields, { add, remove }) => ( + <> + {fields.map((field, index) => ( + + + + + + + + + + + + + + + + + + + {!upstreamDisabled && + (fields.length > 1 ? ( + { + remove(field.name); + }} + /> + ) : null)} + + + + ))} + {!upstreamDisabled && ( + + + + )} + + )} + + ); const renderTimeUnit = () => ms; diff --git a/src/pages/Route/constants.ts b/src/pages/Route/constants.ts index 435dbe92e86f0d..0620bbd8beeec9 100644 --- a/src/pages/Route/constants.ts +++ b/src/pages/Route/constants.ts @@ -60,6 +60,7 @@ export const DEFAULT_STEP_2_DATA: RouteModule.Step2Data = { upstreamHostList: [{} as RouteModule.UpstreamHost], upstreamHeaderList: [], upstreamPath: undefined, + type: 'roundrobin', mappingStrategy: undefined, rewriteType: 'keep', timeout: { @@ -82,3 +83,18 @@ export const INIT_CHART = { selected: {}, hovered: {}, }; + +export const HASH_KEY_LIST = [ + 'remote_addr', + 'host', + 'uri', + 'server_name', + 'server_addr', + 'request_uri', + 'query_string', + 'remote_port', + 'hostname', + 'arg_id', +]; + +export const HASH_ON_LIST = ['vars', 'header', 'cookie', 'consumer']; diff --git a/src/pages/Route/transform.ts b/src/pages/Route/transform.ts index 02ce6dedc8b26d..dae7d91edb3051 100644 --- a/src/pages/Route/transform.ts +++ b/src/pages/Route/transform.ts @@ -30,6 +30,12 @@ export const transformStepData = ({ upstream_header[header.header_name] = header.header_value || ''; }); + const chashData: any = {}; + if (step2Data.type === 'chash') { + chashData.key = step2Data.key; + chashData.hash_on = step2Data.hash_on; + } + let redirect: RouteModule.Redirect = {}; if (step1Data.redirectOption === 'disabled') { redirect = {}; @@ -70,7 +76,8 @@ export const transformStepData = ({ return [key, operator, value]; }), upstream: { - type: 'roundrobin', + type: step2Data.type, + ...chashData, nodes, timeout: step2Data.timeout, }, @@ -199,6 +206,9 @@ export const transformRouteData = (data: RouteModule.Body) => { const step2Data: RouteModule.Step2Data = { upstream_protocol, upstreamHeaderList, + type: upstream ? upstream.type : 'roundrobin', + hash_on: upstream ? upstream.hash_on : undefined, + key: upstream ? upstream.key : undefined, upstreamHostList: transformUpstreamNodes(upstream?.nodes), upstream_id, upstreamPath: upstream_path?.to, diff --git a/src/pages/Route/typing.d.ts b/src/pages/Route/typing.d.ts index 56d4e7a7d489fc..9fc25dc6b62004 100644 --- a/src/pages/Route/typing.d.ts +++ b/src/pages/Route/typing.d.ts @@ -86,6 +86,9 @@ declare namespace RouteModule { type Step2Data = { upstream_protocol: 'http' | 'https' | 'keep'; + type: 'roundrobin' | 'chash'; + hash_on?: string; + key?: string; upstreamHostList: UpstreamHost[]; mappingStrategy: string | undefined; rewriteType: string | undefined; @@ -121,6 +124,8 @@ declare namespace RouteModule { vars: [string, Operator, string][]; upstream: { type: 'roundrobin' | 'chash'; + hash_on?: string; + key?: string; nodes: { [key: string]: number; }; diff --git a/src/pages/Upstream/components/Step1.tsx b/src/pages/Upstream/components/Step1.tsx index 9ac7f733909934..cfbf2b433d0f87 100644 --- a/src/pages/Upstream/components/Step1.tsx +++ b/src/pages/Upstream/components/Step1.tsx @@ -21,7 +21,12 @@ import { useIntl } from 'umi'; import { MinusCircleOutlined, PlusOutlined } from '@ant-design/icons'; import Button from 'antd/es/button'; -import { FORM_ITEM_WITHOUT_LABEL, FORM_ITEM_LAYOUT } from '@/pages/Upstream/constants'; +import { + FORM_ITEM_WITHOUT_LABEL, + FORM_ITEM_LAYOUT, + HASH_KEY_LIST, + HASH_ON_LIST, +} from '@/pages/Upstream/constants'; type Props = { form: FormInstance; @@ -41,7 +46,6 @@ const initialValues = { }; const Step1: React.FC = ({ form, disabled }) => { - const { formatMessage } = useIntl(); const renderUpstreamMeta = () => ( @@ -53,7 +57,11 @@ const Step1: React.FC = ({ form, disabled }) => { required key={field.key} {...(index === 0 ? FORM_ITEM_LAYOUT : FORM_ITEM_WITHOUT_LABEL)} - label={index === 0 ? formatMessage({ id: 'upstream.step.backend.server.domain.or.ip' }) : ''} + label={ + index === 0 + ? formatMessage({ id: 'upstream.step.backend.server.domain.or.ip' }) + : '' + } extra={ index === 0 ? formatMessage({ id: 'upstream.step.domain.name.default.analysis' }) @@ -66,7 +74,10 @@ const Step1: React.FC = ({ form, disabled }) => { style={{ marginBottom: 0 }} name={[field.name, 'host']} rules={[ - { required: true, message: formatMessage({ id: 'upstream.step.input.domain.name.or.ip' }) }, + { + required: true, + message: formatMessage({ id: 'upstream.step.input.domain.name.or.ip' }), + }, { pattern: new RegExp( /(^([1-9]?\d|1\d{2}|2[0-4]\d|25[0-5])(\.(25[0-5]|1\d{2}|2[0-4]\d|[1-9]?\d)){3}$|^(?![0-9.]+$)([a-zA-Z0-9_-]+)(\.[a-zA-Z0-9_-]+){0,}$)/, @@ -76,25 +87,48 @@ const Step1: React.FC = ({ form, disabled }) => { }, ]} > - + - + - + = ({ form, disabled }) => { add(); }} > - {formatMessage({ id: 'upstream.step.create' })} + + {formatMessage({ id: 'upstream.step.create' })} )} @@ -138,24 +173,73 @@ const Step1: React.FC = ({ form, disabled }) => { return (
- - + + - + - + + + {() => { + if (form.getFieldValue('type') === 'chash') { + return ( + <> + + + + + + + + ); + } + return null; + }} + {renderUpstreamMeta()} @@ -165,7 +249,9 @@ const Step1: React.FC = ({ form, disabled }) => { @@ -175,7 +261,12 @@ const Step1: React.FC = ({ form, disabled }) => { diff --git a/src/pages/Upstream/constants.ts b/src/pages/Upstream/constants.ts index 25bb12f92c7cc7..c9e2306e125edf 100644 --- a/src/pages/Upstream/constants.ts +++ b/src/pages/Upstream/constants.ts @@ -18,9 +18,6 @@ export const FORM_ITEM_LAYOUT = { labelCol: { span: 6, }, - wrapperCol: { - span: 18, - }, }; export const FORM_ITEM_WITHOUT_LABEL = { @@ -29,3 +26,18 @@ export const FORM_ITEM_WITHOUT_LABEL = { sm: { span: 20, offset: 6 }, }, }; + +export const HASH_KEY_LIST = [ + 'remote_addr', + 'host', + 'uri', + 'server_name', + 'server_addr', + 'request_uri', + 'query_string', + 'remote_port', + 'hostname', + 'arg_id', +]; + +export const HASH_ON_LIST = ['vars', 'header', 'cookie', 'consumer'];