From af357c00f74772375b74273b76808747f2b9c4f9 Mon Sep 17 00:00:00 2001 From: zhongjie Date: Fri, 6 Nov 2020 17:35:55 +0800 Subject: [PATCH 01/14] 1.pom add the Nacos dependencies; 2.use Nacos to refresh the config; 3.refactor Apollo listener for compatible with Nacos; 4.refactor application.yml file and add related config. --- pom.xml | 12 +++ src/main/java/we/FizzGatewayApplication.java | 4 +- src/main/java/we/config/ApolloConfig.java | 15 +++ .../java/we/config/AppConfigProperties.java | 2 + src/main/java/we/config/SystemConfig.java | 37 ++++++- .../controller/ManagerConfigController.java | 2 + src/main/java/we/filter/PreFilter.java | 3 + src/main/java/we/fizz/ConfigLoader.java | 2 + src/main/java/we/fizz/input/ScriptHelper.java | 4 +- .../java/we/plugin/auth/ApiConfigService.java | 23 ++++- .../java/we/plugin/stat/StatPluginFilter.java | 4 + src/main/resources/application.yml | 97 ++++++++++++++----- 12 files changed, 172 insertions(+), 33 deletions(-) create mode 100644 src/main/java/we/config/ApolloConfig.java diff --git a/pom.xml b/pom.xml index 41a21d4..deff66d 100644 --- a/pom.xml +++ b/pom.xml @@ -37,6 +37,7 @@ 2.13.3 4.1.53.Final 4.5.13 + 0.2.7 @@ -148,6 +149,17 @@ 2.2.5.RELEASE + + com.alibaba.boot + nacos-config-spring-boot-starter + ${nacos.version} + + + com.alibaba.boot + nacos-discovery-spring-boot-starter + ${nacos.version} + + org.apache.commons commons-pool2 diff --git a/src/main/java/we/FizzGatewayApplication.java b/src/main/java/we/FizzGatewayApplication.java index 319b5ed..25d46ae 100644 --- a/src/main/java/we/FizzGatewayApplication.java +++ b/src/main/java/we/FizzGatewayApplication.java @@ -1,6 +1,6 @@ package we; -import com.ctrip.framework.apollo.spring.annotation.EnableApolloConfig; +import com.alibaba.nacos.spring.context.annotation.config.NacosPropertySource; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration; @@ -12,7 +12,7 @@ import org.springframework.cloud.client.discovery.EnableDiscoveryClient; exclude = {ErrorWebFluxAutoConfiguration.class, RedisAutoConfiguration.class, RedisReactiveAutoConfiguration.class}, scanBasePackages = {"we"} ) -@EnableApolloConfig +@NacosPropertySource(dataId = "application", groupId = "fizz-gateway", autoRefreshed = true) @EnableDiscoveryClient public class FizzGatewayApplication { diff --git a/src/main/java/we/config/ApolloConfig.java b/src/main/java/we/config/ApolloConfig.java new file mode 100644 index 0000000..f41e8a6 --- /dev/null +++ b/src/main/java/we/config/ApolloConfig.java @@ -0,0 +1,15 @@ +package we.config; + +import com.ctrip.framework.apollo.spring.annotation.EnableApolloConfig; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Configuration; + +/** + * Apollo config + * @author zhongjie + */ +@ConditionalOnProperty(name = "apollo.enabled") +@EnableApolloConfig +@Configuration +public class ApolloConfig { +} diff --git a/src/main/java/we/config/AppConfigProperties.java b/src/main/java/we/config/AppConfigProperties.java index 5e19b1d..268131c 100644 --- a/src/main/java/we/config/AppConfigProperties.java +++ b/src/main/java/we/config/AppConfigProperties.java @@ -17,6 +17,7 @@ package we.config; +import com.alibaba.nacos.api.config.annotation.NacosValue; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Configuration; @@ -27,6 +28,7 @@ import org.springframework.context.annotation.Configuration; @Configuration public class AppConfigProperties { + @NacosValue(value = "${spring.profiles.active}", autoRefreshed = true) @Value("${spring.profiles.active}") private String env; diff --git a/src/main/java/we/config/SystemConfig.java b/src/main/java/we/config/SystemConfig.java index 0d8bab6..4911ff4 100644 --- a/src/main/java/we/config/SystemConfig.java +++ b/src/main/java/we/config/SystemConfig.java @@ -17,10 +17,12 @@ package we.config; +import com.alibaba.nacos.api.config.annotation.NacosValue; import com.ctrip.framework.apollo.model.ConfigChange; import com.ctrip.framework.apollo.model.ConfigChangeEvent; import com.ctrip.framework.apollo.spring.annotation.ApolloConfigChangeListener; +import org.springframework.util.ObjectUtils; import we.plugin.auth.GatewayGroup; import we.util.Constants; import we.util.JacksonUtils; @@ -61,6 +63,7 @@ public class SystemConfig { // // private Set currentServerGatewayGroupSet; + @NacosValue(value = "${spring.profiles.active}") @Value("${spring.profiles.active}") private String profile; @@ -140,11 +143,9 @@ public class SystemConfig { String nv = c.getNewValue(); log.info(p + " old: " + ov + ", new: " + nv); if (p.equals("log.response-body")) { - logResponseBody = Boolean.valueOf(nv); - afterLogResponseBodySet(); + this.updateLogResponseBody(Boolean.parseBoolean(nv)); } else if (p.equals("log.headers")) { - logHeaders = nv; - afterLogHeadersSet(); + this.updateLogHeaders(nv); } /*else if (p.equals("gateway-group")) { gatewayGroup = nv; afterGatewayGroupSet(); @@ -152,4 +153,32 @@ public class SystemConfig { } ); } + + private void updateLogResponseBody(boolean newValue) { + logResponseBody = newValue; + this.afterLogResponseBodySet(); + } + + private void updateLogHeaders(String newValue) { + logHeaders = newValue; + afterLogHeadersSet(); + } + + @NacosValue(value = "${log.response-body:false}", autoRefreshed = true) + public void setLogResponseBody(boolean logResponseBody) { + if (this.logResponseBody == logResponseBody) { + return; + } + log.info("log.response-body old: " + this.logResponseBody + ", new: " + logResponseBody); + this.updateLogResponseBody(logResponseBody); + } + + @NacosValue(value = "${log.headers:x}", autoRefreshed = true) + public void setLogHeaders(String logHeaders) { + if (ObjectUtils.nullSafeEquals(this.logHeaders, logHeaders)) { + return; + } + log.info("log.headers old: " + this.logHeaders + ", new: " + logHeaders); + this.updateLogHeaders(logHeaders); + } } diff --git a/src/main/java/we/controller/ManagerConfigController.java b/src/main/java/we/controller/ManagerConfigController.java index 92fa2f3..eb2929b 100644 --- a/src/main/java/we/controller/ManagerConfigController.java +++ b/src/main/java/we/controller/ManagerConfigController.java @@ -17,6 +17,7 @@ package we.controller; +import com.alibaba.nacos.api.config.annotation.NacosValue; import org.springframework.beans.factory.annotation.Value; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.PostMapping; @@ -44,6 +45,7 @@ import java.util.stream.Collectors; @RestController @RequestMapping(value = "/managerConfig") public class ManagerConfigController { + @NacosValue(value = "${fizz.manager.config.key:fizz-manager-key}", autoRefreshed = true) @Value("${fizz.manager.config.key:fizz-manager-key}") private String key; diff --git a/src/main/java/we/filter/PreFilter.java b/src/main/java/we/filter/PreFilter.java index 1e2241e..7d7dcc1 100644 --- a/src/main/java/we/filter/PreFilter.java +++ b/src/main/java/we/filter/PreFilter.java @@ -17,6 +17,7 @@ package we.filter; +import com.alibaba.nacos.api.config.annotation.NacosValue; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -56,9 +57,11 @@ public class PreFilter extends ProxyAggrFilter { private static final FilterResult succFr = FilterResult.SUCCESS(PRE_FILTER); + @NacosValue(value = "${spring.profiles.active}") @Value("${spring.profiles.active}") private String profile; + @NacosValue(value = "${b-services:x}") @Value("${b-services:x}") private Set bServices = new HashSet<>(); diff --git a/src/main/java/we/fizz/ConfigLoader.java b/src/main/java/we/fizz/ConfigLoader.java index e8a661c..81254a9 100644 --- a/src/main/java/we/fizz/ConfigLoader.java +++ b/src/main/java/we/fizz/ConfigLoader.java @@ -20,6 +20,7 @@ package we.fizz; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; +import com.alibaba.nacos.api.config.annotation.NacosValue; import we.config.AppConfigProperties; import we.fizz.input.ClientInputConfig; import we.fizz.input.Input; @@ -69,6 +70,7 @@ public class ConfigLoader { @Resource(name = AGGREGATE_REACTIVE_REDIS_TEMPLATE) private ReactiveStringRedisTemplate reactiveStringRedisTemplate; + @NacosValue(value = "${fizz.aggregate.read-local-config-flag:false}", autoRefreshed = true) @Value("${fizz.aggregate.read-local-config-flag:false}") private Boolean readLocalConfigFlag; diff --git a/src/main/java/we/fizz/input/ScriptHelper.java b/src/main/java/we/fizz/input/ScriptHelper.java index a6644d9..eee3aa8 100644 --- a/src/main/java/we/fizz/input/ScriptHelper.java +++ b/src/main/java/we/fizz/input/ScriptHelper.java @@ -29,7 +29,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.alibaba.fastjson.JSON; -import com.ctrip.framework.apollo.core.utils.StringUtils; +import org.springframework.util.StringUtils; import we.constants.CommonConstants; import we.exception.StopAndResponseException; @@ -57,7 +57,7 @@ public class ScriptHelper { Script script = new Script(); script.setType((String) scriptCfg.get("type")); script.setSource((String) scriptCfg.get("source")); - if (StringUtils.isBlank(script.getType()) || StringUtils.isBlank(script.getSource())) { + if (!StringUtils.hasText(script.getType()) || !StringUtils.hasText(script.getSource())) { return null; } diff --git a/src/main/java/we/plugin/auth/ApiConfigService.java b/src/main/java/we/plugin/auth/ApiConfigService.java index 84751f4..31e6b8d 100644 --- a/src/main/java/we/plugin/auth/ApiConfigService.java +++ b/src/main/java/we/plugin/auth/ApiConfigService.java @@ -17,6 +17,7 @@ package we.plugin.auth; +import com.alibaba.nacos.api.config.annotation.NacosValue; import com.ctrip.framework.apollo.model.ConfigChange; import com.ctrip.framework.apollo.model.ConfigChangeEvent; import com.ctrip.framework.apollo.spring.annotation.ApolloConfigChangeListener; @@ -30,6 +31,7 @@ import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.stereotype.Service; +import org.springframework.util.ObjectUtils; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -75,13 +77,26 @@ public class ApiConfigService { k -> { ConfigChange cc = cce.getChange(k); if (cc.getPropertyName().equalsIgnoreCase("serviceWhiteList")) { - log.info("old service white list: " + cc.getOldValue()); - serviceWhiteList = cc.getNewValue(); - afterServiceWhiteListSet(); + this.updateServiceWhiteList(cc.getOldValue(), cc.getNewValue()); } } ); } + + private void updateServiceWhiteList(String oldValue, String newValue) { + if (ObjectUtils.nullSafeEquals(oldValue, newValue)) { + return; + } + log.info("old service white list: " + oldValue); + serviceWhiteList = newValue; + afterServiceWhiteListSet(); + } + + @NacosValue(value = "${serviceWhiteList:x}", autoRefreshed = true) + public void setServiceWhiteList(String serviceWhiteList) { + this.updateServiceWhiteList(this.serviceWhiteList, serviceWhiteList); + } + public void afterServiceWhiteListSet() { if (StringUtils.isNotBlank(serviceWhiteList)) { whiteListSet.clear(); @@ -94,6 +109,7 @@ public class ApiConfigService { } } + @NacosValue(value = "${auth.compatible-wh:false}", autoRefreshed = true) @Value("${auth.compatible-wh:false}") private boolean compatibleWh; @@ -109,6 +125,7 @@ public class ApiConfigService { @Autowired(required = false) private CustomAuth customAuth; + @NacosValue(value = "${openServiceWhiteList:false}", autoRefreshed = true) @Value("${openServiceWhiteList:false}") private boolean openServiceWhiteList = false; diff --git a/src/main/java/we/plugin/stat/StatPluginFilter.java b/src/main/java/we/plugin/stat/StatPluginFilter.java index a314537..8eb25d6 100644 --- a/src/main/java/we/plugin/stat/StatPluginFilter.java +++ b/src/main/java/we/plugin/stat/StatPluginFilter.java @@ -17,6 +17,7 @@ package we.plugin.stat; +import com.alibaba.nacos.api.config.annotation.NacosValue; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -63,12 +64,15 @@ public class StatPluginFilter extends PluginFilter { private static final String reqTime = "\"reqTime\":"; + @NacosValue(value = "${stat.open:false}", autoRefreshed = true) @Value("${stat.open:false}") private boolean statOpen = false; + @NacosValue(value = "${stat.channel:fizz_access_stat}", autoRefreshed = true) @Value("${stat.channel:fizz_access_stat}") private String fizzAccessStatChannel; + @NacosValue(value = "${stat.topic:}", autoRefreshed = true) @Value("${stat.topic:}") private String fizzAccessStatTopic; diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index eaa6ac7..365f21e 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -1,27 +1,80 @@ -#apollo: -# bootstrap: -# enabled: true -# namespaces: application -# eagerLoad: -# enabled: true +# if you do not use Apollo, ignore the follow config +######################### Apollo config start ##################################### +apollo: + # if use Apollo set this flag to true + enabled: false + bootstrap: + # if use Apollo set this flag to true + enabled: false + namespaces: application + eagerLoad: + # if use Apollo set this flag to true + enabled: false +######################### Apollo config end ####################################### -spring.profiles.active: dev +# if you do not use Nacos, ignore the follow config +######################### Nacos config start ###################################### +nacos: + config: + # if use Nacos config set this flag to true + enabled: false + # need replace + server-addr: localhost:8848 + auto-refresh: true + group: fizz-gateway + data-id: application + type: PROPERTIES + # need replace + namespace: c37ecd3b-e8b3-42cc-ba94-98e931e33683 + discovery: + # if use Nacos discovery set this flag to true + enabled: false + # need replace + server-addr: localhost:8848 + auto-register: true +######################### Nacos config end ####################################### -server.port: 8600 +# if you do not use Eureka, ignore the follow config +######################### Eureka config start #################################### +eureka: + client: + # if use Eureka set this flag to true + enabled: false + serviceUrl: + # need replace + defaultZone: http://localhost:6600/eureka/ + instance: + prefer-ip-address: true +######################### Eureka config end ###################################### -eureka.instance.prefer-ip-address: true -eureka.client.serviceUrl.defaultZone: http://localhost:6600/eureka/ -spring.application.name: fizz-gateway -spring.cloud.loadbalancer.ribbon.enabled: false +server: + port: 8600 +spring: + profiles: + active: dev + application: + name: fizz-gateway + cloud: + loadbalancer: + ribbon: + enabled: false -aggregate.redis.host: localhost -aggregate.redis.port: 6379 -aggregate.redis.password: 123456 -aggregate.redis.database: 10 +aggregate: + redis: + # need replace + host: localhost + # need replace + port: 6379 + # need replace + password: 123456 + # need replace + database: 9 +proxy-webclient: + name: proxy +aggr-webclient: + name: aggr +fizz-web-client: + timeout: 20000 +log: + headers: COOKIE,FIZZ-APPID,FIZZ-SECRETKEY,FIZZ-SIGN,FIZZ-TS,FIZZ-RSV -proxy-webclient.name: proxy -aggr-webclient.name: aggr - -fizz-web-client.timeout: 20000 - -log.headers: COOKIE,FIZZ-APPID,FIZZ-SECRETKEY,FIZZ-SIGN,FIZZ-TS,FIZZ-RSV From ded954a2b5be14ded2bf7c3209649f3b2edf1b78 Mon Sep 17 00:00:00 2001 From: zhongjie Date: Mon, 9 Nov 2020 15:05:05 +0800 Subject: [PATCH 02/14] refactor the hard code with Eureka to support optional Eureka and Nacos. --- .../AbstractDiscoveryClientUriSelector.java | 17 ++++++ .../we/proxy/DisableDiscoveryUriSelector.java | 19 +++++++ .../we/proxy/DiscoveryClientUriSelector.java | 16 ++++++ src/main/java/we/proxy/EurekaUriSelector.java | 55 +++++++++++++++++++ src/main/java/we/proxy/FizzWebClient.java | 43 ++------------- src/main/java/we/proxy/NacosUriSelector.java | 46 ++++++++++++++++ 6 files changed, 157 insertions(+), 39 deletions(-) create mode 100644 src/main/java/we/proxy/AbstractDiscoveryClientUriSelector.java create mode 100644 src/main/java/we/proxy/DisableDiscoveryUriSelector.java create mode 100644 src/main/java/we/proxy/DiscoveryClientUriSelector.java create mode 100644 src/main/java/we/proxy/EurekaUriSelector.java create mode 100644 src/main/java/we/proxy/NacosUriSelector.java diff --git a/src/main/java/we/proxy/AbstractDiscoveryClientUriSelector.java b/src/main/java/we/proxy/AbstractDiscoveryClientUriSelector.java new file mode 100644 index 0000000..94ab1de --- /dev/null +++ b/src/main/java/we/proxy/AbstractDiscoveryClientUriSelector.java @@ -0,0 +1,17 @@ +package we.proxy; + +import we.util.Constants; +import we.util.ThreadContext; + +/** + * Abstract implementation of {@code DiscoveryClientUriSelector} + * + * @author zhongjie + */ +abstract public class AbstractDiscoveryClientUriSelector implements DiscoveryClientUriSelector { + + protected String buildUri(String ipAddr, int port, String path) { + StringBuilder b = ThreadContext.getStringBuilder(); + return b.append(Constants.Symbol.HTTP_PROTOCOL_PREFIX).append(ipAddr).append(Constants.Symbol.COLON).append(port).append(path).toString(); + } +} diff --git a/src/main/java/we/proxy/DisableDiscoveryUriSelector.java b/src/main/java/we/proxy/DisableDiscoveryUriSelector.java new file mode 100644 index 0000000..093225f --- /dev/null +++ b/src/main/java/we/proxy/DisableDiscoveryUriSelector.java @@ -0,0 +1,19 @@ +package we.proxy; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; +import org.springframework.stereotype.Service; + +/** + * The disable implementation of {@code DiscoveryClientUriSelector}, used when Nacos and Eureka discovery are not enabled. + * + * @author zhongjie + */ + +@ConditionalOnExpression("${nacos.discovery.enabled} == false and ${eureka.client.enabled} == false") +@Service +public class DisableDiscoveryUriSelector implements DiscoveryClientUriSelector { + @Override + public String getNextUri(String service, String relativeUri) { + throw new RuntimeException("No " + service + " because discovery disabled", null, false, false) {}; + } +} diff --git a/src/main/java/we/proxy/DiscoveryClientUriSelector.java b/src/main/java/we/proxy/DiscoveryClientUriSelector.java new file mode 100644 index 0000000..8d5f326 --- /dev/null +++ b/src/main/java/we/proxy/DiscoveryClientUriSelector.java @@ -0,0 +1,16 @@ +package we.proxy; + +/** + * A {@code DiscoveryClientUriSelector} is used to select the uri for the next request + * + * @author zhongjie + */ +public interface DiscoveryClientUriSelector { + /** + * find a instance of service by discovery and return the uri that http://{instance-ip-addr}:{instance-port}{relativeUri} + * @param service service name + * @param relativeUri relative uri + * @return the uri for the next request + */ + String getNextUri(String service, String relativeUri); +} diff --git a/src/main/java/we/proxy/EurekaUriSelector.java b/src/main/java/we/proxy/EurekaUriSelector.java new file mode 100644 index 0000000..a355549 --- /dev/null +++ b/src/main/java/we/proxy/EurekaUriSelector.java @@ -0,0 +1,55 @@ +package we.proxy; + +import com.netflix.appinfo.InstanceInfo; +import com.netflix.discovery.EurekaClient; +import com.netflix.discovery.shared.Applications; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.List; + +/** + * The Eureka implementation of {@code DiscoveryClientUriSelector} + * + * @author zhongjie + */ +@ConditionalOnProperty(value = "eureka.client.enabled", matchIfMissing = true) +@Service +public class EurekaUriSelector extends AbstractDiscoveryClientUriSelector { + + @Resource + private EurekaClient eurekaClient; + + @Override + public String getNextUri(String service, String relativeUri) { + InstanceInfo inst = roundRobinChoose1instFrom(service); + return buildUri(inst.getIPAddr(), inst.getPort(), relativeUri); + } + + + // private static List aggrMemberInsts = new ArrayList<>(); + // static { + // InstanceInfo i0 = InstanceInfo.Builder.newBuilder().setAppName("TRIP-MINI").setIPAddr("xxx.25.63.192").setPort(7094).build(); + // aggrMemberInsts.add(i0); + // } + // private static AtomicLong counter = new AtomicLong(0); + // private static final String aggrMember = "trip-mini"; + + + private InstanceInfo roundRobinChoose1instFrom(String service) { + + // if (aggrMember.equals(service)) { + // int idx = (int) (counter.incrementAndGet() % aggrMemberInsts.size()); + // return aggrMemberInsts.get(idx); + // } + + List insts = eurekaClient.getInstancesByVipAddress(service, false); + if (insts == null || insts.isEmpty()) { + throw new RuntimeException("eureka no " + service, null, false, false) {}; + } + Applications apps = eurekaClient.getApplications(); + int index = (int) (apps.getNextIndex(service.toUpperCase(), false).incrementAndGet() % insts.size()); + return insts.get(index); + } +} diff --git a/src/main/java/we/proxy/FizzWebClient.java b/src/main/java/we/proxy/FizzWebClient.java index d1be262..90a550e 100644 --- a/src/main/java/we/proxy/FizzWebClient.java +++ b/src/main/java/we/proxy/FizzWebClient.java @@ -17,10 +17,7 @@ package we.proxy; -import com.netflix.appinfo.InstanceInfo; -import com.netflix.discovery.EurekaClient; -import com.netflix.discovery.shared.Applications; - +import com.alibaba.nacos.api.config.annotation.NacosValue; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; @@ -43,10 +40,7 @@ import we.util.WebUtils; import javax.annotation.PostConstruct; import javax.annotation.Resource; -import java.util.ArrayList; -import java.util.List; import java.util.concurrent.ThreadLocalRandom; -import java.util.concurrent.atomic.AtomicLong; /** * @author hongqiaowei @@ -62,7 +56,7 @@ public class FizzWebClient { private static final String localhost = "localhost"; @Resource - private EurekaClient eurekaClient; + private DiscoveryClientUriSelector discoveryClientUriSelector; @Resource(name = ProxyWebClientConfig.proxyWebClient) private WebClient proxyWebClient; @@ -70,6 +64,7 @@ public class FizzWebClient { @Resource(name = AggrWebClientConfig.aggrWebClient) private WebClient aggrWebClient; + @NacosValue(value = "${fizz-web-client.timeout:-1}") @Value("${fizz-web-client.timeout:-1}") private long timeout = -1; @@ -140,8 +135,7 @@ public class FizzWebClient { // what about multiple nginx instance // current - InstanceInfo inst = roundRobinChoose1instFrom(service); - String uri = buildUri(inst, relativeUri); + String uri = discoveryClientUriSelector.getNextUri(service, relativeUri); return send2uri(originReqIdOrBizId, method, uri, headers, body, cbc); } @@ -225,37 +219,8 @@ public class FizzWebClient { // TODO 请求完成后,做metric, 以反哺后续的请求转发 } - private String buildUri(InstanceInfo inst, String path) { - StringBuilder b = ThreadContext.getStringBuilder(); - return b.append(Constants.Symbol.HTTP_PROTOCOL_PREFIX).append(inst.getIPAddr()).append(Constants.Symbol.COLON).append(inst.getPort()).append(path).toString(); - } - // private static List aggrMemberInsts = new ArrayList<>(); - // static { - // InstanceInfo i0 = InstanceInfo.Builder.newBuilder().setAppName("TRIP-MINI").setIPAddr("xxx.25.63.192").setPort(7094).build(); - // aggrMemberInsts.add(i0); - // } - // private static AtomicLong counter = new AtomicLong(0); - // private static final String aggrMember = "trip-mini"; - - - private InstanceInfo roundRobinChoose1instFrom(String service) { - - // if (aggrMember.equals(service)) { - // int idx = (int) (counter.incrementAndGet() % aggrMemberInsts.size()); - // return aggrMemberInsts.get(idx); - // } - - List insts = eurekaClient.getInstancesByVipAddress(service, false); - if (insts == null || insts.isEmpty()) { - throw new RuntimeException("eureka no " + service, null, false, false) {}; - } - Applications apps = eurekaClient.getApplications(); - int index = (int) (apps.getNextIndex(service.toUpperCase(), false).incrementAndGet() % insts.size()); - return insts.get(index); - } - private String extractServiceOrAddress(String uriOrSvc) { return uriOrSvc.substring(7, uriOrSvc.indexOf(Constants.Symbol.FORWARD_SLASH, 10)); } diff --git a/src/main/java/we/proxy/NacosUriSelector.java b/src/main/java/we/proxy/NacosUriSelector.java new file mode 100644 index 0000000..fa785ae --- /dev/null +++ b/src/main/java/we/proxy/NacosUriSelector.java @@ -0,0 +1,46 @@ +package we.proxy; + +import com.alibaba.nacos.api.exception.NacosException; +import com.alibaba.nacos.api.naming.NamingService; +import com.alibaba.nacos.api.naming.pojo.Instance; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; + +/** + * The Nacos implementation of {@code DiscoveryClientUriSelector} + * + * @author zhongjie + */ +@ConditionalOnProperty(value = "nacos.discovery.enabled") +@Service +public class NacosUriSelector extends AbstractDiscoveryClientUriSelector { + private static final Logger log = LoggerFactory.getLogger(NacosUriSelector.class); + + @Resource + private NamingService naming; + + @Override + public String getNextUri(String service, String relativeUri) { + Instance instance = this.selectOneHealthyInstance(service); + return super.buildUri(instance.getIp(), instance.getPort(), relativeUri); + } + + private Instance selectOneHealthyInstance(String service) { + Instance instance = null; + try { + instance = naming.selectOneHealthyInstance(service); + } catch (NacosException e) { + log.warn("Nacos selectOneHealthyInstance({}) exception", service, e); + } + + if (instance == null) { + throw new RuntimeException("Nacos no " + service, null, false, false) {}; + } + + return instance; + } +} From f3b1bbd00728bbf2804c20d0f850fb79eae63e2b Mon Sep 17 00:00:00 2001 From: zhongjie Date: Thu, 12 Nov 2020 14:08:21 +0800 Subject: [PATCH 03/14] refactor the hard code with Eureka to support optional Eureka and Nacos. --- src/main/java/we/proxy/NacosUriSelector.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/we/proxy/NacosUriSelector.java b/src/main/java/we/proxy/NacosUriSelector.java index fa785ae..28eab8c 100644 --- a/src/main/java/we/proxy/NacosUriSelector.java +++ b/src/main/java/we/proxy/NacosUriSelector.java @@ -1,5 +1,6 @@ package we.proxy; +import com.alibaba.nacos.api.annotation.NacosInjected; import com.alibaba.nacos.api.exception.NacosException; import com.alibaba.nacos.api.naming.NamingService; import com.alibaba.nacos.api.naming.pojo.Instance; @@ -8,8 +9,6 @@ import org.slf4j.LoggerFactory; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.stereotype.Service; -import javax.annotation.Resource; - /** * The Nacos implementation of {@code DiscoveryClientUriSelector} * @@ -20,7 +19,7 @@ import javax.annotation.Resource; public class NacosUriSelector extends AbstractDiscoveryClientUriSelector { private static final Logger log = LoggerFactory.getLogger(NacosUriSelector.class); - @Resource + @NacosInjected private NamingService naming; @Override From 1f02caabbe126ff7058d79fc82e77fe0e2a4a95c Mon Sep 17 00:00:00 2001 From: zhongjie Date: Thu, 12 Nov 2020 14:33:51 +0800 Subject: [PATCH 04/14] application.yml add nacos register group name config. --- src/main/resources/application.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 365f21e..1b0c449 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -32,6 +32,8 @@ nacos: # need replace server-addr: localhost:8848 auto-register: true + register: + group-name: fizz-gateway ######################### Nacos config end ####################################### # if you do not use Eureka, ignore the follow config From 2e817109dd1b082ffecf1173c6c5452e3c29a589 Mon Sep 17 00:00:00 2001 From: zhongjie Date: Tue, 17 Nov 2020 10:36:48 +0800 Subject: [PATCH 05/14] 1.update the nacos uri selector to find the same group instance. 2.update version to 1.2.0. 3.update the readme doc. --- README.md | 20 +++++---- pom.xml | 2 +- sh/boot.sh | 2 +- src/main/java/we/proxy/NacosUriSelector.java | 43 +++++++++++++++++++- 4 files changed, 56 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index f9041d1..8969457 100644 --- a/README.md +++ b/README.md @@ -66,6 +66,7 @@ A Managerment API Gateway in Java . Fizz Gateway 是一个基于 Java开发的 | v1.0.0 | v1.0.0 | v1.0.0 | | v1.1.0 | v1.1.0 | v1.1.0 | | v1.1.1 | v1.1.1 | v1.1.1 | +| v1.2.0 | v1.2.0 | v1.1.1 | 请根据社区版的版本下载对应的管理后台版本 @@ -93,13 +94,13 @@ A Managerment API Gateway in Java . Fizz Gateway 是一个基于 Java开发的 ##### 管理后台服务端(fizz-manager-professional) -1. 首次安装执行`fizz-manager-professional-1.1.1-mysql.sql`数据库脚本 -2. 将`application-prod.yml`、`boot.sh`、`fizz-manager-professional-1.1.1.jar`拷贝到`/data/webapps/fizz-manager-professional`目录下 +1. 首次安装执行`fizz-manager-professional-1.2.0-mysql.sql`数据库脚本 +2. 将`application-prod.yml`、`boot.sh`、`fizz-manager-professional-1.2.0.jar`拷贝到`/data/webapps/fizz-manager-professional`目录下 3. 修改`application-prod.yml`文件,将相关配置修改成部署环境的配置 4. 修改`boot.sh`文件,将`RUN_CMD`变量值修改成部署环境的JAVA实际路径 5. 执行 `chmod +x boot.sh` 命令给`boot.sh`增加执行权限 6. 执行 `./boot.sh start` 命令启动服务,支持 start/stop/restart/status命令 -7. 服务启动后访问 http://IP:8000/fizz-manager (将IP替换成服务部署机器IP地址),使用超级管理员账户`admin`密码`Aa123!`登录 +7. 服务启动后访问前端登录地址,使用超级管理员账户`admin`密码`Aa123!`登录 ##### 管理后台前端(fizz-admin-professional) @@ -126,11 +127,14 @@ server { #### 二、安装fizz-gateway-community社区版 -说明:如果使用apollo配置中心,可把application.yml文件内容迁到配置中心(apollo上应用名为:fizz-gateway);使用不使用apollo可去掉下面启动命令里的apollo参数。 +说明: + +1. 支持配置中心:apollo、nacos,支持注册中心:eureka、nacos,详细配置方法查看application.yml文件。 +2. 如果使用apollo配置中心,可把application.yml文件内容迁到配置中心(apollo上应用名为:fizz-gateway);如果不使用apollo可去掉下面启动命令里的apollo参数。 安装方式一:脚本启动: -1. 下载fizz-gateway-community的最新代码,修改application.yml配置文件里eureka、redis的配置,使用maven命令`mvn clean package -DskipTests=true`构建并把构建好的fizz-gateway-community-1.1.1.jar和boot.sh放同一目录 +1. 下载fizz-gateway-community的最新代码,修改application.yml配置文件里配置中心、注册中心、redis的配置,使用maven命令`mvn clean package -DskipTests=true`构建并把构建好的fizz-gateway-community-1.2.0.jar和boot.sh放同一目录 2. 修改boot.sh脚本的apollo连接,JVM内存配置 3. 执行 `./boot.sh start` 命令启动服务,支持 start/stop/restart/status命令 @@ -138,13 +142,13 @@ server { 1. 本地clone仓库上的最新代码 2. 将项目fizz-gateway导入IDE -3. 导入完成后设置项目启动配置及修改application.yml配置文件里eureka、redis的配置,在VM选项中加入`-Denv=dev -Dapollo.meta=http://localhost:66`(Apollo配置中心地址) +3. 导入完成后设置项目启动配置及修改application.yml配置文件里配置中心、注册中心、redis的配置,在VM选项中加入`-Denv=dev -Dapollo.meta=http://localhost:66`(Apollo配置中心地址) 安装方式三:jar启动: -1. 本地clone仓库上的最新代码,修改application.yml配置文件里eureka、redis的配置 +1. 本地clone仓库上的最新代码,修改application.yml配置文件里配置中心、注册中心、redis的配置 2. 在项目根目录fizz-gateway-community下执行Maven命令`mvn clean package -DskipTests=true`打包 -3. 进入target目录,使用命令`java -jar -Denv=DEV -Dapollo.meta=http://localhost:66 fizz-gateway-community-1.1.1.jar`启动服务 +3. 进入target目录,使用命令`java -jar -Denv=DEV -Dapollo.meta=http://localhost:66 fizz-gateway-community-1.2.0.jar`启动服务 最后访问网关,地址形式为:http://127.0.0.1:8600/proxy/[服务名]/[API Path] diff --git a/pom.xml b/pom.xml index deff66d..691a288 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ we fizz-gateway-community - 1.1.1 + 1.2.0 fizz-gateway-community diff --git a/sh/boot.sh b/sh/boot.sh index 9f0a930..5e6eb48 100644 --- a/sh/boot.sh +++ b/sh/boot.sh @@ -6,7 +6,7 @@ cd `dirname $0` #变量定义 APOLLO_META_SERVER=http://localhost:66 ENV=dev -APP_NAME=fizz-gateway-community-1.1.1.jar +APP_NAME=fizz-gateway-community-1.2.0.jar APP_DEP_DIR=/data/webapps/fizz-gateway APP_LOG_DIR=/data/logs/fizz-gateway JAVA_CMD=/usr/local/java/bin/java diff --git a/src/main/java/we/proxy/NacosUriSelector.java b/src/main/java/we/proxy/NacosUriSelector.java index 28eab8c..fff4144 100644 --- a/src/main/java/we/proxy/NacosUriSelector.java +++ b/src/main/java/we/proxy/NacosUriSelector.java @@ -1,5 +1,7 @@ package we.proxy; +import com.alibaba.boot.nacos.discovery.properties.NacosDiscoveryProperties; +import com.alibaba.boot.nacos.discovery.properties.Register; import com.alibaba.nacos.api.annotation.NacosInjected; import com.alibaba.nacos.api.exception.NacosException; import com.alibaba.nacos.api.naming.NamingService; @@ -8,6 +10,11 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.stereotype.Service; +import org.springframework.util.StringUtils; + +import javax.annotation.PostConstruct; +import java.util.Collections; +import java.util.List; /** * The Nacos implementation of {@code DiscoveryClientUriSelector} @@ -19,8 +26,34 @@ import org.springframework.stereotype.Service; public class NacosUriSelector extends AbstractDiscoveryClientUriSelector { private static final Logger log = LoggerFactory.getLogger(NacosUriSelector.class); + public NacosUriSelector(NacosDiscoveryProperties discoveryProperties) { + this.discoveryProperties = discoveryProperties; + } + @NacosInjected private NamingService naming; + private NacosDiscoveryProperties discoveryProperties; + private String groupName; + private List clusterNameList; + private boolean useGroupName; + private boolean userClusterName; + + @PostConstruct + public void init() { + Register register = discoveryProperties.getRegister(); + if (register != null) { + this.groupName = register.getGroupName(); + if (StringUtils.hasText(groupName)) { + this.useGroupName = true; + } + String clusterName = register.getClusterName(); + if (StringUtils.hasText(clusterName)) { + this.userClusterName = true; + this.clusterNameList = Collections.singletonList(clusterName); + } + + } + } @Override public String getNextUri(String service, String relativeUri) { @@ -31,7 +64,15 @@ public class NacosUriSelector extends AbstractDiscoveryClientUriSelector { private Instance selectOneHealthyInstance(String service) { Instance instance = null; try { - instance = naming.selectOneHealthyInstance(service); + if (useGroupName && userClusterName) { + instance = naming.selectOneHealthyInstance(service, groupName, clusterNameList); + } else if (useGroupName) { + instance = naming.selectOneHealthyInstance(service, groupName); + } else if (userClusterName) { + instance = naming.selectOneHealthyInstance(service, clusterNameList); + } else { + instance = naming.selectOneHealthyInstance(service); + } } catch (NacosException e) { log.warn("Nacos selectOneHealthyInstance({}) exception", service, e); } From 4caedf7c00aed09011dbb6c1b1f94cf95eceff29 Mon Sep 17 00:00:00 2001 From: Francis Dong Date: Tue, 17 Nov 2020 15:01:08 +0800 Subject: [PATCH 06/14] update: use WebUtils to get request path --- src/main/java/we/filter/FizzGatewayFilter.java | 2 +- src/main/java/we/util/WebUtils.java | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/we/filter/FizzGatewayFilter.java b/src/main/java/we/filter/FizzGatewayFilter.java index 27873f5..7c4860f 100644 --- a/src/main/java/we/filter/FizzGatewayFilter.java +++ b/src/main/java/we/filter/FizzGatewayFilter.java @@ -74,7 +74,7 @@ public class FizzGatewayFilter implements WebFilter { ServerHttpRequest request = exchange.getRequest(); ServerHttpResponse serverHttpResponse = exchange.getResponse(); - String path = request.getURI().getPath(); + String path = WebUtils.PATH_PREFIX + WebUtils.getServiceId(exchange) + WebUtils.getReqPath(exchange); String method = request.getMethodValue(); AggregateResource aggregateResource = configLoader.matchAggregateResource(method, path); if (aggregateResource == null) { diff --git a/src/main/java/we/util/WebUtils.java b/src/main/java/we/util/WebUtils.java index 09fef91..43e43ea 100644 --- a/src/main/java/we/util/WebUtils.java +++ b/src/main/java/we/util/WebUtils.java @@ -73,6 +73,8 @@ public abstract class WebUtils { private static final String response = " response "; private static final String originIp = "originIp"; + + public static final String PATH_PREFIX = "/proxy/"; public static String getHeaderValue(ServerWebExchange exchange, String header) { return exchange.getRequest().getHeaders().getFirst(header); From beef51be1adf648ad9e95f1e89630832b14fea5c Mon Sep 17 00:00:00 2001 From: Francis Dong Date: Wed, 18 Nov 2020 14:56:47 +0800 Subject: [PATCH 07/14] #14 support redirect in aggregation --- docs/404.html | 6 +-- docs/CNAME | 1 - docs/aggr_config_redirect.png | Bin 0 -> 115526 bytes .../js/{10.b57afcaa.js => 10.13320b99.js} | 2 +- .../js/{11.21242c7f.js => 11.a76c2e4c.js} | 2 +- .../js/{12.61089982.js => 12.f815cfa2.js} | 2 +- .../js/{14.62d9a88b.js => 14.7e909813.js} | 2 +- .../js/{15.0358b10e.js => 15.791d6b9d.js} | 2 +- .../js/{16.43a475d2.js => 16.4ae255f1.js} | 2 +- .../js/{21.dca6f5c4.js => 21.081e4e30.js} | 2 +- .../js/{22.db62cc12.js => 22.0c08546e.js} | 2 +- .../js/{23.5b796ecf.js => 23.94679012.js} | 2 +- .../js/{24.72fe0b8b.js => 24.9c5c2990.js} | 2 +- .../js/{25.bbf8bff1.js => 25.aead8972.js} | 2 +- .../js/{26.70321f43.js => 26.b4625fe9.js} | 2 +- .../js/{27.505a813e.js => 27.20a7e33d.js} | 2 +- .../js/{28.cdddd7aa.js => 28.3d35b618.js} | 2 +- .../js/{30.0222f21c.js => 30.7591e88a.js} | 2 +- .../js/{5.a59b20e1.js => 5.abc10683.js} | 2 +- .../js/{7.00dd2642.js => 7.e3b70354.js} | 2 +- .../js/{8.645ad4e8.js => 8.a4432ff1.js} | 2 +- .../js/{9.9eb9244c.js => 9.b1740bdf.js} | 2 +- .../js/{app.86b5ae26.js => app.60575df2.js} | 4 +- docs/guide/admin/index.html | 6 +-- docs/guide/aggregate/configuration.html | 8 ++-- docs/guide/aggregate/index.html | 6 +-- docs/guide/aggregate/overview.html | 6 +-- docs/guide/benchmark/index.html | 6 +-- docs/guide/index.html | 6 +-- docs/guide/installation/index.html | 6 +-- docs/guide/intro/index.html | 6 +-- docs/guide/manager/manager_aggregate.html | 6 +-- .../manager/manager_aggregate_approve.html | 6 +-- .../manager_aggregate_approve_op_log.html | 6 +-- .../manager/manager_aggregate_my_apply.html | 6 +-- .../manager/manager_aggregate_op_log.html | 6 +-- docs/guide/manager/manager_api_auth.html | 6 +-- docs/guide/manager/manager_app_id.html | 6 +-- .../manager_gateway_aggregate_cache.html | 6 +-- docs/guide/manager/manager_gateway_group.html | 6 +-- docs/guide/manager/manager_overview.html | 6 +-- docs/guide/manager/manager_plugin.html | 6 +-- docs/guide/manager/manager_role.html | 6 +-- docs/guide/manager/manager_service.html | 6 +-- .../manager/manager_source_statistics.html | 6 +-- docs/guide/manager/manager_user.html | 6 +-- docs/guide/plugin/index.html | 6 +-- docs/guide/proxy/index.html | 6 +-- docs/index.html | 4 +- .../java/we/constants/CommonConstants.java | 9 ++++ .../java/we/exception/RedirectException.java | 45 ++++++++++++++++++ .../exception/StopAndResponseException.java | 2 +- .../filter/FilterExceptionHandlerConfig.java | 14 +++++- src/main/java/we/fizz/input/ScriptHelper.java | 9 ++++ 54 files changed, 179 insertions(+), 105 deletions(-) delete mode 100644 docs/CNAME create mode 100644 docs/aggr_config_redirect.png rename docs/assets/js/{10.b57afcaa.js => 10.13320b99.js} (92%) rename docs/assets/js/{11.21242c7f.js => 11.a76c2e4c.js} (97%) rename docs/assets/js/{12.61089982.js => 12.f815cfa2.js} (99%) rename docs/assets/js/{14.62d9a88b.js => 14.7e909813.js} (99%) rename docs/assets/js/{15.0358b10e.js => 15.791d6b9d.js} (96%) rename docs/assets/js/{16.43a475d2.js => 16.4ae255f1.js} (95%) rename docs/assets/js/{21.dca6f5c4.js => 21.081e4e30.js} (97%) rename docs/assets/js/{22.db62cc12.js => 22.0c08546e.js} (98%) rename docs/assets/js/{23.5b796ecf.js => 23.94679012.js} (98%) rename docs/assets/js/{24.72fe0b8b.js => 24.9c5c2990.js} (99%) rename docs/assets/js/{25.bbf8bff1.js => 25.aead8972.js} (97%) rename docs/assets/js/{26.70321f43.js => 26.b4625fe9.js} (98%) rename docs/assets/js/{27.505a813e.js => 27.20a7e33d.js} (97%) rename docs/assets/js/{28.cdddd7aa.js => 28.3d35b618.js} (97%) rename docs/assets/js/{30.0222f21c.js => 30.7591e88a.js} (95%) rename docs/assets/js/{5.a59b20e1.js => 5.abc10683.js} (79%) rename docs/assets/js/{7.00dd2642.js => 7.e3b70354.js} (81%) rename docs/assets/js/{8.645ad4e8.js => 8.a4432ff1.js} (97%) rename docs/assets/js/{9.9eb9244c.js => 9.b1740bdf.js} (94%) rename docs/assets/js/{app.86b5ae26.js => app.60575df2.js} (87%) create mode 100644 src/main/java/we/exception/RedirectException.java diff --git a/docs/404.html b/docs/404.html index af112bc..c7c4b5b 100644 --- a/docs/404.html +++ b/docs/404.html @@ -7,13 +7,13 @@ - + -

404

Looks like we've got some broken links.
+ - + diff --git a/docs/CNAME b/docs/CNAME deleted file mode 100644 index 692ef2e..0000000 --- a/docs/CNAME +++ /dev/null @@ -1 +0,0 @@ -fizzgate.com \ No newline at end of file diff --git a/docs/aggr_config_redirect.png b/docs/aggr_config_redirect.png new file mode 100644 index 0000000000000000000000000000000000000000..cf4c26552b6946a39c036b7c244ffe3fdd099963 GIT binary patch literal 115526 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

s2tP7QjhVCelO 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 s&e< set foo bar\nOK\nredis> get foo\n"bar"\n')])])]),s("h3",{attrs:{id:"安装apollo配置中心"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#安装apollo配置中心"}},[a._v("#")]),a._v(" 安装Apollo配置中心")]),a._v(" "),s("p",[a._v("说明: apollo是可选组件,如果不使用apollo可使用本地配置文件(application.yml), 如果不使用apollo可跳过此步骤。")]),a._v(" "),s("p",[a._v("安装步骤详见apollo官方文档: "),s("a",{attrs:{href:"https://github.com/ctripcorp/apollo/wiki/Quick-Start",target:"_blank",rel:"noopener noreferrer"}},[s("OutboundLink")],1)]),a._v(" "),s("h3",{attrs:{id:"安装eureka服务注册中心"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#安装eureka服务注册中心"}},[a._v("#")]),a._v(" 安装Eureka服务注册中心")]),a._v(" "),s("p",[a._v("环境要求:")]),a._v(" "),s("ul",[s("li",[a._v("JDK 1.8 或以上版本")]),a._v(" "),s("li",[a._v("Tomcat 6.0.10 或以上版本 (如使用spring cloud已内置)")])]),a._v(" "),s("ol",[s("li",[a._v("安装JDK 1.8")])]),a._v(" "),s("p",[a._v("1)下载JDK,如: jdk-8u192-linux-x64.tar.gz")]),a._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[a._v("tar -zxvf jdk-8u192-linux-x64.tar.gz\nmv jdk1.8.0_192 /usr/local/\n\n")])])]),s("p",[a._v("2)设置JDK环境变量,将下面内容追回到/etc/profile文件后面")]),a._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[a._v("JAVA_HOME=/usr/local/jdk/jdk1.8.0_192\nJRE_HOME=$JAVA_HOME/jre\nPATH=$PATH:$JAVA_HOME/bin:$JRE_HOME/bin\nCLASSPATH=:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JRE_HOME/lib/dt.jar\nexport JAVA_HOME JRE_HOME PATH CLASSPATH\n\n")])])]),s("p",[a._v("3)执行以下命令全环境变量生效:")]),a._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[a._v("source /etc/profile\n\n")])])]),s("p",[a._v("4)查看是否安装成功")]),a._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[a._v("java -version\n")])])]),s("ol",{attrs:{start:"2"}},[s("li",[a._v("安装eureka")])]),a._v(" "),s("p",[a._v("1)使用IDE创建一个spring boot项目,如:sc-eureka-server")]),a._v(" "),s("p",[a._v("pom.xml:")]),a._v(" "),s("div",{staticClass:"language-xml extra-class"},[s("pre",{pre:!0,attrs:{class:"language-xml"}},[s("code",[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("<")]),a._v("dependency")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(">")])]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("<")]),a._v("groupId")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(">")])]),a._v("org.springframework.cloud"),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("")])]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("<")]),a._v("artifactId")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(">")])]),a._v("spring-cloud-starter-netflix-eureka-server"),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("")])]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("")])]),a._v("\n")])])]),s("p",[a._v("在启动类上添加@EnableEurekaServer注解来启用Euerka注册中心功能:")]),a._v(" "),s("div",{staticClass:"language-java extra-class"},[s("pre",{pre:!0,attrs:{class:"language-java"}},[s("code",[s("span",{pre:!0,attrs:{class:"token annotation punctuation"}},[a._v("@SpringBootApplication")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token annotation punctuation"}},[a._v("@EnableEurekaServer")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("public")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("class")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[a._v("ScEurekaServerApplication")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n\n\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("public")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("static")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("void")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("main")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[a._v("String")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("]")]),a._v(" args"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token class-name"}},[a._v("SpringApplication")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("run")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[a._v("ScEurekaServerApplication")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(".")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("class")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v(" args"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),a._v("\n\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),a._v("\n")])])]),s("p",[a._v("application.properties配置文件:")]),a._v(" "),s("div",{staticClass:"language-properties extra-class"},[s("pre",{pre:!0,attrs:{class:"language-properties"}},[s("code",[s("span",{pre:!0,attrs:{class:"token attr-name"}},[a._v("spring.application.name")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),s("span",{pre:!0,attrs:{class:"token attr-value"}},[a._v("sc-eureka-server")]),a._v("\n\n"),s("span",{pre:!0,attrs:{class:"token attr-name"}},[a._v("server.port")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),s("span",{pre:!0,attrs:{class:"token attr-value"}},[a._v("8761")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token attr-name"}},[a._v("eureka.instance.hostname")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),s("span",{pre:!0,attrs:{class:"token attr-value"}},[a._v("localhost")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token attr-name"}},[a._v("eureka.client.registerWithEureka")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),s("span",{pre:!0,attrs:{class:"token attr-value"}},[a._v("false")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token attr-name"}},[a._v("eureka.client.fetchRegistry")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),s("span",{pre:!0,attrs:{class:"token attr-value"}},[a._v("false")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token attr-name"}},[a._v("eureka.server.enableSelfPreservation")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),s("span",{pre:!0,attrs:{class:"token attr-value"}},[a._v("false")]),a._v("\n")])])]),s("p",[a._v("2) maven构建并运行sc-eureka-server应用, 启动后访问地址http://localhost:8761/可以看到Eureka注册中心的界面")]),a._v(" "),s("p",[a._v("3)把target/sc-eureka-server-1.0.0.jar传到linux服务器上运行. (仅以单机部署为例)")]),a._v(" "),s("div",{staticClass:"language-shell extra-class"},[s("pre",{pre:!0,attrs:{class:"language-shell"}},[s("code",[a._v("nohub java -jar sc-eureka-server-1.0.0.jar "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("&")]),a._v(" \n")])])]),s("p",[a._v("4)eureka客户端的注册地址为:http://localhost:8761/eureka/ (替换localhost为服务器的IP)")]),a._v(" "),s("div",{staticClass:"language-properties extra-class"},[s("pre",{pre:!0,attrs:{class:"language-properties"}},[s("code",[s("span",{pre:!0,attrs:{class:"token attr-name"}},[a._v("eureka.client.serviceUrl.defaultZone")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token attr-value"}},[a._v("http://localhost:8761/eureka/")]),a._v("\n")])])]),s("h2",{attrs:{id:"安装fizz"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#安装fizz"}},[a._v("#")]),a._v(" 安装Fizz")]),a._v(" "),s("h3",{attrs:{id:"管理后台"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#管理后台"}},[a._v("#")]),a._v(" 管理后台")]),a._v(" "),s("p",[a._v("从github的releases(https://github.com/wehotel/fizz-gateway-community/releases)下载 fizz-manager-professional 和 fizz-admin-professional 的安装包")]),a._v(" "),s("ul",[s("li",[a._v("管理后台服务端(fizz-manager-professional)")])]),a._v(" "),s("ol",[s("li",[a._v("首次安装执行"),s("code",[a._v("fizz-manager-professional-1.1.0-mysql.sql")]),a._v("数据库脚本,低版本升级执行"),s("code",[a._v("update")]),a._v("目录下的升级脚本")]),a._v(" "),s("li",[a._v("将"),s("code",[a._v("application-prod.yml")]),a._v("、"),s("code",[a._v("boot.sh")]),a._v("、"),s("code",[a._v("fizz-manager-professional-1.1.0.jar")]),a._v("拷贝到"),s("code",[a._v("/data/webapps/fizz-manager-professional")]),a._v("目录下")]),a._v(" "),s("li",[a._v("修改"),s("code",[a._v("application-prod.yml")]),a._v("文件,将相关配置修改成部署环境的配置")]),a._v(" "),s("li",[a._v("修改"),s("code",[a._v("boot.sh")]),a._v("文件,将"),s("code",[a._v("RUN_CMD")]),a._v("变量值修改成部署环境的JAVA实际路径")]),a._v(" "),s("li",[a._v("执行 "),s("code",[a._v("chmod +x boot.sh")]),a._v(" 命令给"),s("code",[a._v("boot.sh")]),a._v("增加执行权限")]),a._v(" "),s("li",[a._v("执行 "),s("code",[a._v("./boot.sh start")]),a._v(" 命令启动服务,支持 start/stop/restart(升级发布时需要手动kill原进程)/status命令")]),a._v(" "),s("li",[a._v("服务启动后访问前端登录地址,使用超级管理员账户"),s("code",[a._v("admin")]),a._v("密码"),s("code",[a._v("Aa123!")]),a._v("登录")])]),a._v(" "),s("ul",[s("li",[a._v("管理后台前端(fizz-admin-professional)")])]),a._v(" "),s("p",[a._v("zip资源包解压后,取文件夹【fizzAdmin】放置于服务器静态数据存放目录 如:/home/data/")]),a._v(" "),s("p",[a._v("nginx配置")]),a._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[a._v("server {\n listen 9000;\n server_name localhost:9000;\n location / {\n root /home/data/fizzAdmin;\n }\n location ^~ /api {\n rewrite ^/api/(.*) /$1 break;\n proxy_pass http://127.0.0.1:8000;\n }\n}\n\n# 注:root中地址需与资源包存放目录路径一致\n# 注:http://127.0.0.1:8000 为管理后台(fizz-manager-professional)的访问地址\n")])])]),s("p",[a._v("访问地址")]),a._v(" "),s("p",[a._v("【资源部署服务器IP + 端口号】如:http://127.0.0.1:9000/")]),a._v(" "),s("p",[a._v("(端口号与nginx配置端口号一致)")]),a._v(" "),s("h3",{attrs:{id:"fizz-gateway-community社区版"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#fizz-gateway-community社区版"}},[a._v("#")]),a._v(" fizz-gateway-community社区版")]),a._v(" "),s("p",[a._v("说明:如果使用apollo配置中心,可把application.yml文件内容迁到配置中心(apollo上应用名为:fizz-gateway);使用不使用apollo可去掉下面启动命令里的apollo参数。")]),a._v(" "),s("p",[a._v("脚本启动:")]),a._v(" "),s("ol",[s("li",[a._v("下载fizz-gateway-community的最新代码,修改application.yml配置文件里eureka、redis的配置,使用maven构建好并把构建好的fizz-gateway-community-1.0.0.jar和boot.sh放同一目录")]),a._v(" "),s("li",[a._v("修改boot.sh脚本的apollo连接,JVM内存配置,")]),a._v(" "),s("li",[a._v("执行 "),s("code",[a._v("./boot.sh start")]),a._v(" 命令启动服务,支持 start/stop/restart/status命令")])]),a._v(" "),s("p",[a._v("IDE启动:")]),a._v(" "),s("ol",[s("li",[a._v("本地clone仓库上的最新代码")]),a._v(" "),s("li",[a._v("将项目fizz-gateway导入IDE")]),a._v(" "),s("li",[a._v("导入完成后设置项目启动配置及修改application.yml配置文件里eureka、redis的配置,在VM选项中加入"),s("code",[a._v("-Denv=dev -Dapollo.meta=http://localhost:66")]),a._v("(Apollo配置中心地址)")])]),a._v(" "),s("p",[a._v("jar启动:")]),a._v(" "),s("ol",[s("li",[a._v("本地clone仓库上的最新代码,修改application.yml配置文件里eureka、redis的配置")]),a._v(" "),s("li",[a._v("在项目根目录fizz-gateway-community下执行Maven命令"),s("code",[a._v("mvn clean package -DskipTests=true")]),a._v("打包")]),a._v(" "),s("li",[a._v("进入target目录,使用命令"),s("code",[a._v("java -jar -Denv=DEV -Dapollo.meta=http://localhost:66 fizz-gateway-community-1.0.0.jar")]),a._v("启动服务")])]),a._v(" "),s("p",[a._v("网关访问地址格式:")]),a._v(" "),s("p",[a._v("http://127.0.0.1:8600/proxy/[服务名]/[API Path]")])])}),[],!1,null,null,null);t.default=r.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[12],{359:function(a,t,s){"use strict";s.r(t);var e=s(42),r=Object(e.a)({},(function(){var a=this,t=a.$createElement,s=a._self._c||t;return s("ContentSlotsDistributor",{attrs:{"slot-key":a.$parent.slotKey}},[s("h2",{attrs:{id:"安装依赖"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#安装依赖"}},[a._v("#")]),a._v(" 安装依赖")]),a._v(" "),s("p",[a._v("安装以下依赖软件:")]),a._v(" "),s("ul",[s("li",[a._v("Redis 2.8或以上版本")]),a._v(" "),s("li",[a._v("MySQL 5.7或以上版本")]),a._v(" "),s("li",[a._v("Apollo配置中心 (可选)")]),a._v(" "),s("li",[a._v("Eureka服务注册中心")])]),a._v(" "),s("h3",{attrs:{id:"安装mysql"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#安装mysql"}},[a._v("#")]),a._v(" 安装MySQL")]),a._v(" "),s("ul",[s("li",[a._v("操作系统 CentOS 6.5")]),a._v(" "),s("li",[a._v("MySQL 5.7.30")])]),a._v(" "),s("ol",[s("li",[a._v("下载MySQL")])]),a._v(" "),s("div",{staticClass:"language-shell extra-class"},[s("pre",{pre:!0,attrs:{class:"language-shell"}},[s("code",[s("span",{pre:!0,attrs:{class:"token function"}},[a._v("wget")]),a._v(" https://downloads.mysql.com/archives/get/p/23/file/mysql-5.7.30-1.el6.x86_64.rpm-bundle.tar\n")])])]),s("ol",{attrs:{start:"2"}},[s("li",[a._v("解压")])]),a._v(" "),s("div",{staticClass:"language-shell extra-class"},[s("pre",{pre:!0,attrs:{class:"language-shell"}},[s("code",[s("span",{pre:!0,attrs:{class:"token function"}},[a._v("tar")]),a._v(" -xvf mysql-5.7.30-1.el6.x86_64.rpm-bundle.tar\n")])])]),s("ol",{attrs:{start:"3"}},[s("li",[a._v("安装")])]),a._v(" "),s("div",{staticClass:"language-shell extra-class"},[s("pre",{pre:!0,attrs:{class:"language-shell"}},[s("code",[s("span",{pre:!0,attrs:{class:"token function"}},[a._v("sudo")]),a._v(" yum "),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("install")]),a._v(" mysql-community-"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("server,client,common,libs"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),a._v("-*\n")])])]),s("ol",{attrs:{start:"4"}},[s("li",[a._v("启动")])]),a._v(" "),s("div",{staticClass:"language-shell extra-class"},[s("pre",{pre:!0,attrs:{class:"language-shell"}},[s("code",[s("span",{pre:!0,attrs:{class:"token function"}},[a._v("sudo")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("service")]),a._v(" mysqld start\n")])])]),s("p",[a._v("启动成功会显示以下信息:")]),a._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[a._v("[root@localhost ~]# sudo service mysqld start\nInitializing MySQL database: [ OK ]\nStarting mysqld: [ OK ]\n")])])]),s("ol",{attrs:{start:"5"}},[s("li",[a._v("初始密码")])]),a._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[a._v("sudo grep 'temporary password' /var/log/mysqld.log\n")])])]),s("ol",{attrs:{start:"6"}},[s("li",[a._v("使用初始密码登录")])]),a._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[a._v("mysql -uroot -p\n")])])]),s("ol",{attrs:{start:"7"}},[s("li",[a._v("修改密码")])]),a._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[a._v("ALTER USER 'root'@'localhost' IDENTIFIED BY 'MyNewPass4!';\n")])])]),s("ol",{attrs:{start:"8"}},[s("li",[a._v("退出登录")])]),a._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[a._v("quit\n")])])]),s("h3",{attrs:{id:"安装redis-6-0-8"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#安装redis-6-0-8"}},[a._v("#")]),a._v(" 安装Redis 6.0.8")]),a._v(" "),s("ol",[s("li",[a._v("下载解压并编译")])]),a._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[a._v("$ wget http://download.redis.io/releases/redis-6.0.8.tar.gz\n$ tar xzf redis-6.0.8.tar.gz\n$ cd redis-6.0.8\n$ make\n")])])]),s("ol",{attrs:{start:"2"}},[s("li",[a._v("启动redis")])]),a._v(" "),s("p",[a._v("运行编译后的文件:")]),a._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[a._v("$ src/redis-server\n")])])]),s("ol",{attrs:{start:"3"}},[s("li",[a._v("客户端连接")])]),a._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[a._v('$ src/redis-cli\nredis> set foo bar\nOK\nredis> get foo\n"bar"\n')])])]),s("h3",{attrs:{id:"安装apollo配置中心"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#安装apollo配置中心"}},[a._v("#")]),a._v(" 安装Apollo配置中心")]),a._v(" "),s("p",[a._v("说明: apollo是可选组件,如果不使用apollo可使用本地配置文件(application.yml), 如果不使用apollo可跳过此步骤。")]),a._v(" "),s("p",[a._v("安装步骤详见apollo官方文档: "),s("a",{attrs:{href:"https://github.com/ctripcorp/apollo/wiki/Quick-Start",target:"_blank",rel:"noopener noreferrer"}},[s("OutboundLink")],1)]),a._v(" "),s("h3",{attrs:{id:"安装eureka服务注册中心"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#安装eureka服务注册中心"}},[a._v("#")]),a._v(" 安装Eureka服务注册中心")]),a._v(" "),s("p",[a._v("环境要求:")]),a._v(" "),s("ul",[s("li",[a._v("JDK 1.8 或以上版本")]),a._v(" "),s("li",[a._v("Tomcat 6.0.10 或以上版本 (如使用spring cloud已内置)")])]),a._v(" "),s("ol",[s("li",[a._v("安装JDK 1.8")])]),a._v(" "),s("p",[a._v("1)下载JDK,如: jdk-8u192-linux-x64.tar.gz")]),a._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[a._v("tar -zxvf jdk-8u192-linux-x64.tar.gz\nmv jdk1.8.0_192 /usr/local/\n\n")])])]),s("p",[a._v("2)设置JDK环境变量,将下面内容追回到/etc/profile文件后面")]),a._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[a._v("JAVA_HOME=/usr/local/jdk/jdk1.8.0_192\nJRE_HOME=$JAVA_HOME/jre\nPATH=$PATH:$JAVA_HOME/bin:$JRE_HOME/bin\nCLASSPATH=:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JRE_HOME/lib/dt.jar\nexport JAVA_HOME JRE_HOME PATH CLASSPATH\n\n")])])]),s("p",[a._v("3)执行以下命令全环境变量生效:")]),a._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[a._v("source /etc/profile\n\n")])])]),s("p",[a._v("4)查看是否安装成功")]),a._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[a._v("java -version\n")])])]),s("ol",{attrs:{start:"2"}},[s("li",[a._v("安装eureka")])]),a._v(" "),s("p",[a._v("1)使用IDE创建一个spring boot项目,如:sc-eureka-server")]),a._v(" "),s("p",[a._v("pom.xml:")]),a._v(" "),s("div",{staticClass:"language-xml extra-class"},[s("pre",{pre:!0,attrs:{class:"language-xml"}},[s("code",[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("<")]),a._v("dependency")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(">")])]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("<")]),a._v("groupId")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(">")])]),a._v("org.springframework.cloud"),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("")])]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("<")]),a._v("artifactId")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(">")])]),a._v("spring-cloud-starter-netflix-eureka-server"),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("")])]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("")])]),a._v("\n")])])]),s("p",[a._v("在启动类上添加@EnableEurekaServer注解来启用Euerka注册中心功能:")]),a._v(" "),s("div",{staticClass:"language-java extra-class"},[s("pre",{pre:!0,attrs:{class:"language-java"}},[s("code",[s("span",{pre:!0,attrs:{class:"token annotation punctuation"}},[a._v("@SpringBootApplication")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token annotation punctuation"}},[a._v("@EnableEurekaServer")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("public")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("class")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[a._v("ScEurekaServerApplication")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n\n\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("public")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("static")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("void")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("main")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[a._v("String")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("]")]),a._v(" args"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token class-name"}},[a._v("SpringApplication")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("run")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[a._v("ScEurekaServerApplication")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(".")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("class")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v(" args"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),a._v("\n\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),a._v("\n")])])]),s("p",[a._v("application.properties配置文件:")]),a._v(" "),s("div",{staticClass:"language-properties extra-class"},[s("pre",{pre:!0,attrs:{class:"language-properties"}},[s("code",[s("span",{pre:!0,attrs:{class:"token attr-name"}},[a._v("spring.application.name")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),s("span",{pre:!0,attrs:{class:"token attr-value"}},[a._v("sc-eureka-server")]),a._v("\n\n"),s("span",{pre:!0,attrs:{class:"token attr-name"}},[a._v("server.port")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),s("span",{pre:!0,attrs:{class:"token attr-value"}},[a._v("8761")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token attr-name"}},[a._v("eureka.instance.hostname")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),s("span",{pre:!0,attrs:{class:"token attr-value"}},[a._v("localhost")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token attr-name"}},[a._v("eureka.client.registerWithEureka")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),s("span",{pre:!0,attrs:{class:"token attr-value"}},[a._v("false")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token attr-name"}},[a._v("eureka.client.fetchRegistry")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),s("span",{pre:!0,attrs:{class:"token attr-value"}},[a._v("false")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token attr-name"}},[a._v("eureka.server.enableSelfPreservation")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),s("span",{pre:!0,attrs:{class:"token attr-value"}},[a._v("false")]),a._v("\n")])])]),s("p",[a._v("2) maven构建并运行sc-eureka-server应用, 启动后访问地址http://localhost:8761/可以看到Eureka注册中心的界面")]),a._v(" "),s("p",[a._v("3)把target/sc-eureka-server-1.0.0.jar传到linux服务器上运行. (仅以单机部署为例)")]),a._v(" "),s("div",{staticClass:"language-shell extra-class"},[s("pre",{pre:!0,attrs:{class:"language-shell"}},[s("code",[a._v("nohub java -jar sc-eureka-server-1.0.0.jar "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("&")]),a._v(" \n")])])]),s("p",[a._v("4)eureka客户端的注册地址为:http://localhost:8761/eureka/ (替换localhost为服务器的IP)")]),a._v(" "),s("div",{staticClass:"language-properties extra-class"},[s("pre",{pre:!0,attrs:{class:"language-properties"}},[s("code",[s("span",{pre:!0,attrs:{class:"token attr-name"}},[a._v("eureka.client.serviceUrl.defaultZone")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token attr-value"}},[a._v("http://localhost:8761/eureka/")]),a._v("\n")])])]),s("h2",{attrs:{id:"安装fizz"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#安装fizz"}},[a._v("#")]),a._v(" 安装Fizz")]),a._v(" "),s("h3",{attrs:{id:"管理后台"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#管理后台"}},[a._v("#")]),a._v(" 管理后台")]),a._v(" "),s("p",[a._v("从github的releases(https://github.com/wehotel/fizz-gateway-community/releases)下载 fizz-manager-professional 和 fizz-admin-professional 的安装包")]),a._v(" "),s("ul",[s("li",[a._v("管理后台服务端(fizz-manager-professional)")])]),a._v(" "),s("ol",[s("li",[a._v("首次安装执行"),s("code",[a._v("fizz-manager-professional-1.1.0-mysql.sql")]),a._v("数据库脚本,低版本升级执行"),s("code",[a._v("update")]),a._v("目录下的升级脚本")]),a._v(" "),s("li",[a._v("将"),s("code",[a._v("application-prod.yml")]),a._v("、"),s("code",[a._v("boot.sh")]),a._v("、"),s("code",[a._v("fizz-manager-professional-1.1.0.jar")]),a._v("拷贝到"),s("code",[a._v("/data/webapps/fizz-manager-professional")]),a._v("目录下")]),a._v(" "),s("li",[a._v("修改"),s("code",[a._v("application-prod.yml")]),a._v("文件,将相关配置修改成部署环境的配置")]),a._v(" "),s("li",[a._v("修改"),s("code",[a._v("boot.sh")]),a._v("文件,将"),s("code",[a._v("RUN_CMD")]),a._v("变量值修改成部署环境的JAVA实际路径")]),a._v(" "),s("li",[a._v("执行 "),s("code",[a._v("chmod +x boot.sh")]),a._v(" 命令给"),s("code",[a._v("boot.sh")]),a._v("增加执行权限")]),a._v(" "),s("li",[a._v("执行 "),s("code",[a._v("./boot.sh start")]),a._v(" 命令启动服务,支持 start/stop/restart(升级发布时需要手动kill原进程)/status命令")]),a._v(" "),s("li",[a._v("服务启动后访问前端登录地址,使用超级管理员账户"),s("code",[a._v("admin")]),a._v("密码"),s("code",[a._v("Aa123!")]),a._v("登录")])]),a._v(" "),s("ul",[s("li",[a._v("管理后台前端(fizz-admin-professional)")])]),a._v(" "),s("p",[a._v("zip资源包解压后,取文件夹【fizzAdmin】放置于服务器静态数据存放目录 如:/home/data/")]),a._v(" "),s("p",[a._v("nginx配置")]),a._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[a._v("server {\n listen 9000;\n server_name localhost:9000;\n location / {\n root /home/data/fizzAdmin;\n }\n location ^~ /api {\n rewrite ^/api/(.*) /$1 break;\n proxy_pass http://127.0.0.1:8000;\n }\n}\n\n# 注:root中地址需与资源包存放目录路径一致\n# 注:http://127.0.0.1:8000 为管理后台(fizz-manager-professional)的访问地址\n")])])]),s("p",[a._v("访问地址")]),a._v(" "),s("p",[a._v("【资源部署服务器IP + 端口号】如:http://127.0.0.1:9000/")]),a._v(" "),s("p",[a._v("(端口号与nginx配置端口号一致)")]),a._v(" "),s("h3",{attrs:{id:"fizz-gateway-community社区版"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#fizz-gateway-community社区版"}},[a._v("#")]),a._v(" fizz-gateway-community社区版")]),a._v(" "),s("p",[a._v("说明:如果使用apollo配置中心,可把application.yml文件内容迁到配置中心(apollo上应用名为:fizz-gateway);使用不使用apollo可去掉下面启动命令里的apollo参数。")]),a._v(" "),s("p",[a._v("脚本启动:")]),a._v(" "),s("ol",[s("li",[a._v("下载fizz-gateway-community的最新代码,修改application.yml配置文件里eureka、redis的配置,使用maven构建好并把构建好的fizz-gateway-community-1.0.0.jar和boot.sh放同一目录")]),a._v(" "),s("li",[a._v("修改boot.sh脚本的apollo连接,JVM内存配置,")]),a._v(" "),s("li",[a._v("执行 "),s("code",[a._v("./boot.sh start")]),a._v(" 命令启动服务,支持 start/stop/restart/status命令")])]),a._v(" "),s("p",[a._v("IDE启动:")]),a._v(" "),s("ol",[s("li",[a._v("本地clone仓库上的最新代码")]),a._v(" "),s("li",[a._v("将项目fizz-gateway导入IDE")]),a._v(" "),s("li",[a._v("导入完成后设置项目启动配置及修改application.yml配置文件里eureka、redis的配置,在VM选项中加入"),s("code",[a._v("-Denv=dev -Dapollo.meta=http://localhost:66")]),a._v("(Apollo配置中心地址)")])]),a._v(" "),s("p",[a._v("jar启动:")]),a._v(" "),s("ol",[s("li",[a._v("本地clone仓库上的最新代码,修改application.yml配置文件里eureka、redis的配置")]),a._v(" "),s("li",[a._v("在项目根目录fizz-gateway-community下执行Maven命令"),s("code",[a._v("mvn clean package -DskipTests=true")]),a._v("打包")]),a._v(" "),s("li",[a._v("进入target目录,使用命令"),s("code",[a._v("java -jar -Denv=DEV -Dapollo.meta=http://localhost:66 fizz-gateway-community-1.0.0.jar")]),a._v("启动服务")])]),a._v(" "),s("p",[a._v("网关访问地址格式:")]),a._v(" "),s("p",[a._v("http://127.0.0.1:8600/proxy/[服务名]/[API Path]")])])}),[],!1,null,null,null);t.default=r.exports}}]); \ No newline at end of file diff --git a/docs/assets/js/14.62d9a88b.js b/docs/assets/js/14.7e909813.js similarity index 99% rename from docs/assets/js/14.62d9a88b.js rename to docs/assets/js/14.7e909813.js index 9678218..94d822a 100644 --- a/docs/assets/js/14.62d9a88b.js +++ b/docs/assets/js/14.7e909813.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[14],{360:function(a,t,s){"use strict";s.r(t);var r=s(42),e=Object(r.a)({},(function(){var a=this,t=a.$createElement,s=a._self._c||t;return s("ContentSlotsDistributor",{attrs:{"slot-key":a.$parent.slotKey}},[s("h2",{attrs:{id:"概述"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#概述"}},[a._v("#")]),a._v(" 概述")]),a._v(" "),s("p",[a._v("接口列表功能用于维护聚合接口,聚合接口从外部调用方角度看是一个简单的接口,通过入参请求获取响应结果,内部实现会调用多个底层后端服务,将多个调用结果聚合转换成外部调用方想要的数据格式,更多详情请查看服务编排介绍,下面介绍接口列表功能的操作。")]),a._v(" "),s("h2",{attrs:{id:"接口列表"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#接口列表"}},[a._v("#")]),a._v(" 接口列表")]),a._v(" "),s("p",[a._v("菜单位置:服务编排 > 接口列表。点击菜单后进入接口列表页面,如图所示。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_list_query.png",alt:"manager_aggregate_list_query"}})]),a._v(" "),s("h2",{attrs:{id:"新增接口"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#新增接口"}},[a._v("#")]),a._v(" 新增接口")]),a._v(" "),s("p",[a._v("点击 新增 按钮弹出新增窗口,如图所示。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_add_1.png",alt:"manager_aggregate_add_1"}})]),a._v(" "),s("h3",{attrs:{id:"基础信息"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#基础信息"}},[a._v("#")]),a._v(" 基础信息")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_add_2.png",alt:"manager_aggregate_add_2"}})]),a._v(" "),s("p",[a._v("所属服务:接口所属服务,更多详情请查看服务管理功能介绍,必选;")]),a._v(" "),s("p",[a._v("接口名:接口名称,用于展示使用,长度不能超过200个字符,必填;")]),a._v(" "),s("p",[a._v("方法:接口请求方法类型,可选GET|POST,必选;")]),a._v(" "),s("p",[a._v("路径:接口请求路径后缀,长度不能超过2000个字符,必填;")]),a._v(" "),s("p",[a._v("开发人员:接口对应负责的开发人员,长度不能超过200个字符;")]),a._v(" "),s("p",[a._v("描述:接口功能描述,长度不能超过2000个字符;")]),a._v(" "),s("p",[a._v("举个例子,所属服务设置my-test-service,方法设置POST,路径设置test-aggregate-post,对应的聚合接口请求为 POST http://{Fizz网关ip地址}:{port端口}/proxy/my-test-service/test-aggregate-post。")]),a._v(" "),s("h3",{attrs:{id:"配置输入"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#配置输入"}},[a._v("#")]),a._v(" 配置输入")]),a._v(" "),s("p",[a._v("聚合接口的入参大部分是通过JSON Schema来定义的,下面先简单地介绍下JSON Schema。")]),a._v(" "),s("h4",{attrs:{id:"json-schema介绍"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#json-schema介绍"}},[a._v("#")]),a._v(" JSON Schema介绍")]),a._v(" "),s("p",[a._v("JSON Schema实际上也是JSON数据,用于标注和验证JSON文档,可以类比于XML Schema,当前最新版本2019-09。")]),a._v(" "),s("p",[a._v("作为普通用户,我们并不需要去了解JSON Schema的规范内容,只要能够构建JSON Schema即可。")]),a._v(" "),s("blockquote",[s("p",[a._v("要理解JSON Schema,首先要理解什么是JSON。JSON是JavaScript Object Notation的缩写,一种简单的数据交换格式。最初JSON是基于JavaScript,广泛的应用于万维网。由于其简洁和清晰的层次结构、易于人阅读等特性,使得越来越多的场景下被采用。")]),a._v(" "),s("p",[a._v("JSON包含以下数据结构:")]),a._v(" "),s("ul",[s("li",[a._v("object:"),s("div",{staticClass:"language-javascript extra-class"},[s("pre",{pre:!0,attrs:{class:"language-javascript"}},[s("code",[s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"key1"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"value1"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"key2"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"value2"')]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),a._v("\n")])])])]),a._v(" "),s("li",[a._v("array:"),s("div",{staticClass:"language-javascript extra-class"},[s("pre",{pre:!0,attrs:{class:"language-javascript"}},[s("code",[s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("[")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"first"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"second"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"third"')]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("]")]),a._v("\n")])])])]),a._v(" "),s("li",[a._v("number:"),s("div",{staticClass:"language-javascript extra-class"},[s("pre",{pre:!0,attrs:{class:"language-javascript"}},[s("code",[s("span",{pre:!0,attrs:{class:"token number"}},[a._v("42")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token number"}},[a._v("3.1415926")]),a._v("\n")])])])]),a._v(" "),s("li",[a._v("string:"),s("div",{staticClass:"language-javascript extra-class"},[s("pre",{pre:!0,attrs:{class:"language-javascript"}},[s("code",[s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"This is a string"')]),a._v("\n")])])])]),a._v(" "),s("li",[a._v("boolean:"),s("div",{staticClass:"language-javascript extra-class"},[s("pre",{pre:!0,attrs:{class:"language-javascript"}},[s("code",[s("span",{pre:!0,attrs:{class:"token boolean"}},[a._v("true")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token boolean"}},[a._v("false")]),a._v("\n")])])])]),a._v(" "),s("li",[a._v("null:"),s("div",{staticClass:"language-javascript extra-class"},[s("pre",{pre:!0,attrs:{class:"language-javascript"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("null")]),a._v("\n")])])])])]),a._v(" "),s("p",[a._v("通过以上的简单数据类型,就能构造复杂的结构化数据了。下面举两个例子:")]),a._v(" "),s("div",{staticClass:"language-javascript extra-class"},[s("pre",{pre:!0,attrs:{class:"language-javascript"}},[s("code",[s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"name"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"George Washington"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"birthday"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"February 22, 1732"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"address"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"Mount Vernon, Virginia, United States"')]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),a._v("\n")])])]),s("div",{staticClass:"language-javascript extra-class"},[s("pre",{pre:!0,attrs:{class:"language-javascript"}},[s("code",[s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"first_name"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"George"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"last_name"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"Washington"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"birthday"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"1732-02-22"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"address"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"street_address"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"3200 Mount Vernon Memorial Highway"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"city"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"Mount Vernon"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"state"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"Virginia"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"country"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"United States"')]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),a._v("\n")])])]),s("p",[a._v("以上两个例子都是有效的JSON数据,包含一样的有效信息,但是当程序读取数据时,需要准确的知道数据是怎么组织的,比如哪些字段是必须,这些字段是什么类型。这时候JSON Schema就派上用场了,看以下JSON Schema例子:")]),a._v(" "),s("div",{staticClass:"language-javascript extra-class"},[s("pre",{pre:!0,attrs:{class:"language-javascript"}},[s("code",[s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"type"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"object"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"properties"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"first_name"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"type"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"string"')]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"last_name"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"type"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"string"')]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"birthday"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"type"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"string"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"format"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"date"')]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"address"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"type"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"object"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"properties"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"street_address"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"type"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"string"')]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"city"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"type"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"string"')]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"state"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"type"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"string"')]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"country"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"type"')]),a._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"string"')]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),a._v("\n")])])]),s("p",[a._v("用以上JSON Schema验证第一个例子时,验证失败;但是第二个例子验证通过。")]),a._v(" "),s("p",[a._v("JSON Schema本身也是通过JSON编写,其本身也是数据,不是一个计算机程序,只是一种“描述其它数据的结构”的声明格式。这既是长处,也是弱点,JSON Schema可以简洁地描述数据的结构并且自动验证数据,但是对于数据元素间的关系表达就力不能及了。")])]),a._v(" "),s("p",[a._v("更多JSON Schema知识可以阅读"),s("a",{attrs:{href:"https://json-schema.org/understanding-json-schema/",target:"_blank",rel:"noopener noreferrer"}},[a._v("Understanding JSON Schema"),s("OutboundLink")],1),a._v("。")]),a._v(" "),s("h4",{attrs:{id:"请求头部"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#请求头部"}},[a._v("#")]),a._v(" 请求头部")]),a._v(" "),s("p",[a._v("定义聚合接口的请求Header参数。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_add_3.png",alt:"manager_aggregate_add_3"}})]),a._v(" "),s("p",[a._v("举个例子:")]),a._v(" "),s("div",{staticClass:"language-javascript extra-class"},[s("pre",{pre:!0,attrs:{class:"language-javascript"}},[s("code",[s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"type"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"object"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"properties"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"headerParam1"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"type"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"string"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"title"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"请求头参数1"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"titleEn"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"headerParam1"')]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"required"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("[")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"headerParam1"')]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("]")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),a._v("\n")])])]),s("p",[a._v("以上例子定义了必传请求头参数"),s("code",[a._v("headerParam1")]),a._v("。")]),a._v(" "),s("p",[s("code",[a._v("title")]),a._v("字段用于验证失败时提示使用,例如请求接口时没传请求头时会提示“请求头参数1不能为空”(错误提示输出通过校验结果配置,详情请看后文介绍),如图所示。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_add_input_header_1.png",alt:"manager_aggregate_add_input_header_1"}})]),a._v(" "),s("p",[a._v("当定义了语言配置(详情请查看后文的语言配置介绍)选项为英文时会使用"),s("code",[a._v("titleEn")]),a._v("字段用于验证失败时提示使用,例如请求接口时没传请求头时会提示“headerParam1 is missing but it is required”(错误提示输出通过校验结果配置,详情请看后文介绍),如图所示。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_add_input_header_2.png",alt:"manager_aggregate_add_input_header_2"}})]),a._v(" "),s("h4",{attrs:{id:"请求体"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#请求体"}},[a._v("#")]),a._v(" 请求体")]),a._v(" "),s("p",[a._v("定义聚合接口的请求体参数。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_add_4.png",alt:"manager_aggregate_add_4"}})]),a._v(" "),s("p",[a._v("举个例子:")]),a._v(" "),s("div",{staticClass:"language-javascript extra-class"},[s("pre",{pre:!0,attrs:{class:"language-javascript"}},[s("code",[s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"type"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"object"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"properties"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"bodyParam1"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"type"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"string"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"title"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"请求体参数1"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"titleEn"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"bodyParam1"')]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"required"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("[")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"bodyParam1"')]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("]")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),a._v("\n")])])]),s("p",[a._v("以上例子定义了必传请求体参数"),s("code",[a._v("bodyParam1")]),a._v("。")]),a._v(" "),s("p",[s("code",[a._v("title")]),a._v("字段用于验证失败时提示使用,例如请求接口时没传请求体参数时会提示“请求体参数1不能为空”(错误提示输出通过校验结果配置,详情请看后文介绍),如图所示。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_add_input_body_1.png",alt:"manager_aggregate_add_input_body_1"}})]),a._v(" "),s("p",[a._v("当定义了语言配置(详情请查看后文的语言配置介绍)选项为英文时会使用"),s("code",[a._v("titleEn")]),a._v("字段用于验证失败时提示使用,例如请求接口时没传请求体参数时会提示“bodyParam1 is missing but it is required”(错误提示输出通过校验结果配置,详情请看后文介绍),如图所示。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_add_input_body_2.png",alt:"manager_aggregate_add_input_body_2"}})]),a._v(" "),s("h4",{attrs:{id:"query参数"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#query参数"}},[a._v("#")]),a._v(" Query参数")]),a._v(" "),s("p",[a._v("定义聚合接口的Query参数。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_add_5.png",alt:"manager_aggregate_add_5"}})]),a._v(" "),s("p",[a._v("举个例子:")]),a._v(" "),s("div",{staticClass:"language-javascript extra-class"},[s("pre",{pre:!0,attrs:{class:"language-javascript"}},[s("code",[s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"type"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"object"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"properties"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"queryParam1"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"type"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"string"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"title"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"query参数1"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"titleEn"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"queryParam1"')]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"required"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("[")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"queryParam1"')]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("]")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),a._v("\n")])])]),s("p",[a._v("以上例子定义了必传Query参数"),s("code",[a._v("queryParam1")]),a._v("。")]),a._v(" "),s("p",[s("code",[a._v("title")]),a._v("字段用于验证失败时提示使用,例如请求接口时没传Query参数时会提示“query参数1不能为空”(错误提示输出通过校验结果配置,详情请看后文介绍),如图所示。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_add_input_query_1.png",alt:"manager_aggregate_add_input_query_1"}})]),a._v(" "),s("p",[a._v("当定义了语言配置(详情请查看后文的语言配置介绍)选项为英文时会使用"),s("code",[a._v("titleEn")]),a._v("字段用于验证失败时提示使用,例如请求接口时没传Query参数时会提示“queryParam1 is missing but it is required”(错误提示输出通过校验结果配置,详情请看后文介绍),如图所示。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_add_input_query_2.png",alt:"manager_aggregate_add_input_query_2"}})]),a._v(" "),s("h4",{attrs:{id:"脚本校验"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#脚本校验"}},[a._v("#")]),a._v(" 脚本校验")]),a._v(" "),s("p",[a._v("对于JSON Schema规范无法覆盖的校验场景可以使用脚本对入参进行更加灵活的处理。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_add_6.png",alt:"manager_aggregate_add_6"}})]),a._v(" "),s("p",[a._v("点击 新增 按钮后弹出脚本配置窗口,如图所示。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_add_7.png",alt:"manager_aggregate_add_7"}})]),a._v(" "),s("p",[a._v("脚本类型:可选javascript|groovy,必选;")]),a._v(" "),s("p",[a._v("脚本内容:所选的脚本类型语言编写的入参验证脚本,必填。")]),a._v(" "),s("p",[a._v("举个例子:")]),a._v(" "),s("div",{staticClass:"language-javascript extra-class"},[s("pre",{pre:!0,attrs:{class:"language-javascript"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[a._v("// javascript脚本函数名不能修改")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("function")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("dyFunc")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token parameter"}},[a._v("paramsJsonStr")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[a._v("// 上下文, 数据结构请参考 context.js")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("var")]),a._v(" context "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token constant"}},[a._v("JSON")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("parse")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),a._v("paramsJsonStr"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[a._v("'context'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[a._v("// common为内置的上下文便捷操作工具类,详情请参考common.js;例如:")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[a._v("// var data = common.getStepRespBody(context, 'step2', 'request1', 'data');")]),a._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[a._v("// do something")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("var")]),a._v(" headerParam1 "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v(" common"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("getInputReqHeader")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),a._v("context"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v("'headerParam1'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("var")]),a._v(" bodyParam1 "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v(" common"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("getInputReqBody")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),a._v("context"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v("'bodyParam1'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("var")]),a._v(" queryParam1 "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v(" common"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("getInputReqParam")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),a._v("context"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v("'queryParam1'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("var")]),a._v(" result "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("new")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[a._v("Array")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("if")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),a._v("headerParam1 "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("!=")]),a._v(" bodyParam1"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n result"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("push")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"headerParam1与bodyParam1不一致"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("if")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),a._v("queryParam1 "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("!=")]),a._v(" bodyParam1"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n result"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("push")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"queryParam1与bodyParam1不一致"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("if")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),a._v("headerParam1 "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("!=")]),a._v(" queryParam1"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n result"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("push")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"headerParam1与queryParam1不一致"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),a._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[a._v("// 返回结果为Array或Object时要先转为json字符串")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("return")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token constant"}},[a._v("JSON")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("stringify")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),a._v("result"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),a._v("\n\n")])])]),s("p",[a._v("以上例子使用javascript编写参数校验,限制入参"),s("code",[a._v("headerParam1")]),a._v("、"),s("code",[a._v("bodyParam1")]),a._v("、"),s("code",[a._v("queryParam1")]),a._v("必须一致,不一致将提示错误信息(错误提示输出通过校验结果配置,详情请看后文介绍),如图所示。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_add_input_script.png",alt:"manager_aggregate_add_input_script"}})]),a._v(" "),s("h4",{attrs:{id:"语言配置"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#语言配置"}},[a._v("#")]),a._v(" 语言配置")]),a._v(" "),s("p",[a._v("聚合接口默认使用中文响应校验失败提示,通过配置可通过入参选择不同的提示语言,目前支持中文、英文提示(已满足我们的业务使用场景,有其他语言要求的小伙伴可以联系我们添加)。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_add_8.png",alt:"manager_aggregate_add_8"}})]),a._v(" "),s("p",[a._v("字段:入参字段值,例如"),s("code",[a._v("input.request.body.languageCode")]),a._v("使用请求体参数"),s("code",[a._v("languageCode")]),a._v("的值来决定使用哪种语言;")]),a._v(" "),s("p",[a._v("中文:中文与入参字段值的映射关系,例如配置"),s("code",[a._v("0")]),a._v(",当请求入参字段值为"),s("code",[a._v("0")]),a._v("时使用中文提示校验结果;")]),a._v(" "),s("p",[a._v("英文:英文与入参字段值的映射关系,例如配置"),s("code",[a._v("1")]),a._v(",当请求入参字段值为"),s("code",[a._v("1")]),a._v("时使用中文提示校验结果。")]),a._v(" "),s("h3",{attrs:{id:"配置步骤"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#配置步骤"}},[a._v("#")]),a._v(" 配置步骤")]),a._v(" "),s("p",[a._v("聚合接口调用底层服务是通过多个step实现的,多个step串行执行,每个step包含多个request(对底层服务接口的调用),同个step里的多个request并行执行,后执行的step可以获取已执行step的执行结果,更多详情请查看服务编排文章的介绍,下面介绍配置步骤的使用。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_add_9.png",alt:"manager_aggregate_add_9"}})]),a._v(" "),s("p",[a._v("是否执行完此步骤后结束:勾选后实际请求只执行完该步骤后即响应结果,不执行后续步骤,用于调试使用;")]),a._v(" "),s("p",[a._v("请求方法:调用底层服务接口的请求类型,可选GET|POST,必选;")]),a._v(" "),s("p",[a._v("默认URL:调用底层服务接口的默认URL,当Fizz网关启动环境没有配置URL时使用该默认URL;")]),a._v(" "),s("p",[a._v("开发环境URL:开发环境调用底层服务接口的URL,当Fizz网关启动使用spring.profiles.active=dev时使用该URL;")]),a._v(" "),s("p",[a._v("测试环境URL:测试环境调用底层服务接口的URL,当Fizz网关启动使用spring.profiles.active=test时使用该URL;")]),a._v(" "),s("p",[a._v("预生产环境URL:预生产环境调用底层服务接口的URL,当Fizz网关启动使用spring.profiles.active=pre时使用该URL;")]),a._v(" "),s("p",[a._v("生产环境URL:生产环境调用底层服务接口的URL,当Fizz网关启动使用spring.profiles.active=prod时使用该URL;")]),a._v(" "),s("p",[a._v("超时时间(毫秒):调用底层服务接口的超时时间,超时抛出异常,单位毫秒;")]),a._v(" "),s("p",[a._v("Fallback:可选stop|continue,控制当调用底层服务接口失败后是否继续执行后续操作;")]),a._v(" "),s("p",[a._v("请求预处理:勾选后可配置预处理脚本,预处理脚本返回true时才执行调用底层服务接口。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_add_10.png",alt:"manager_aggregate_add_10"}})]),a._v(" "),s("p",[a._v("配置入参:配置调用底层服务接口的请求参数;")]),a._v(" "),s("p",[a._v("配置响应:配置调用底层服务接口的响应内容。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_add_11.png",alt:"manager_aggregate_add_11"}})]),a._v(" "),s("p",[a._v("配置步骤结果:配置step执行完成后的响应内容。")]),a._v(" "),s("h3",{attrs:{id:"配置输出"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#配置输出"}},[a._v("#")]),a._v(" 配置输出")]),a._v(" "),s("p",[a._v("配置聚合接口调用完成的响应内容。在响应体、响应头配置中可以配置简单的响应固定值、响应引用值,对于需要逻辑处理得到结果的响应可以通过脚本配置灵活处理,如图所示。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_add_12.png",alt:"manager_aggregate_add_12"}})]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_add_13.png",alt:"manager_aggregate_add_13"}})]),a._v(" "),s("h3",{attrs:{id:"校验结果"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#校验结果"}},[a._v("#")]),a._v(" 校验结果")]),a._v(" "),s("p",[a._v("配置聚合接口入参校验失败后的响应内容,在响应体、响应头配置中可以配置简单的响应固定值、响应引用值,对于需要逻辑处理得到结果的响应可以通过脚本配置灵活处理,如图所示。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_add_14.png",alt:"manager_aggregate_add_14"}})]),a._v(" "),s("p",[a._v("校验结果有一个专用的引用值"),s("code",[a._v("validateMsg")]),a._v(",该引用值用于存放入参验证错误提示信息。")]),a._v(" "),s("h3",{attrs:{id:"保存接口"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#保存接口"}},[a._v("#")]),a._v(" 保存接口")]),a._v(" "),s("p",[a._v("所有配置完成后点击 保存 按钮,完成聚合接口的配置。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_add_15.png",alt:"manager_aggregate_add_15"}})]),a._v(" "),s("h2",{attrs:{id:"导出接口"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#导出接口"}},[a._v("#")]),a._v(" 导出接口")]),a._v(" "),s("p",[a._v("导出功能将聚合接口以配置文件的形式导出,导出的文件可通过导入功能重新导入系统,当我们的系统分多个环境时,可使用导出导入功能实现聚合接口的快速同步,下面介绍导出功能。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_export_1.png",alt:"manager_aggregate_export_1"}})]),a._v(" "),s("p",[a._v("勾选想到导出的接口,点击 导出 按钮弹出确认窗口,如图所示。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_export_2.png",alt:"manager_aggregate_export_2"}})]),a._v(" "),s("p",[a._v("点击 确定 按钮,浏览器保存配置文件,如图所示。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_export_3.png",alt:"manager_aggregate_export_3"}})]),a._v(" "),s("h2",{attrs:{id:"导入接口"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#导入接口"}},[a._v("#")]),a._v(" 导入接口")]),a._v(" "),s("p",[a._v("导入功能将配置文件中的聚合接口转化成后台的持久化存储,导入的文件可以通过导出功能获取或者通过编写好的聚合配置JSON文件转化得到(转换工具可以联系我们获取)。当我们的系统分多个环境时,可使用导出导入功能实现聚合接口的快速同步,下面介绍导出功能。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_import_1.png",alt:"manager_aggregate_import_1"}})]),a._v(" "),s("p",[a._v("点击 导入 按钮弹出导入配置窗口,如图所示。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_import_2.png",alt:"manager_aggregate_import_2"}})]),a._v(" "),s("p",[a._v("点击 选取文件 按钮后选取要导入的配置文件;")]),a._v(" "),s("p",[a._v("强制覆盖:通过请求类型(GET|POST)、请求路径(/proxy/{service}/{apiPath})可以唯一确定一个聚合接口,当聚合接口已存在时,未勾选该选项时忽略该聚合接口导入,勾选该选项时覆盖已存在的聚合接口配置;")]),a._v(" "),s("p",[a._v("点击 确定 按钮后导入聚合接口配置。")]),a._v(" "),s("h2",{attrs:{id:"调试模式"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#调试模式"}},[a._v("#")]),a._v(" 调试模式")]),a._v(" "),s("p",[a._v("调试模式用于对接口开发过程中的调试使用,当打开调试模式后,Fizz网关会将聚合接口调用底层服务接口的请求响应信息以及耗时、聚合结果、步骤上下文打印到日志中,通过日志可以清楚的了解聚合接口的实际执行情况。调试模式会对网关性能造成影响,因此不建议在生产环境打开调试模式,当调试完成后及时关闭调试模式,避免打印过多日志造成资源浪费,下面介绍调试模式的使用。")]),a._v(" "),s("p",[a._v("勾选想要打开调试模式的接口,点击 打开调试模式 按钮弹出确认窗口,如图所示。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_debug_mode_1.png",alt:"manager_aggregate_debug_mode_1"}})]),a._v(" "),s("p",[a._v("点击 确定 按钮确认打开调试模式。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_debug_mode_2.png",alt:"manager_aggregate_debug_mode_2"}})]),a._v(" "),s("p",[a._v("勾选想要关闭调试模式的接口,点击 关闭调试模式 按钮弹出确认窗口,如图所示。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_debug_mode_3.png",alt:"manager_aggregate_debug_mode_3"}})]),a._v(" "),s("p",[a._v("点击 确定 按钮确认关闭调试模式。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_debug_mode_4.png",alt:"manager_aggregate_debug_mode_4"}})]),a._v(" "),s("h2",{attrs:{id:"编辑接口"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#编辑接口"}},[a._v("#")]),a._v(" 编辑接口")]),a._v(" "),s("p",[a._v("点击 编辑 按钮弹出编辑窗口,如图所示。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_edit_1.png",alt:"manager_aggregate_edit_1"}})]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_edit_2.png",alt:"manager_aggregate_edit_2"}})]),a._v(" "),s("h2",{attrs:{id:"删除接口"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#删除接口"}},[a._v("#")]),a._v(" 删除接口")]),a._v(" "),s("p",[a._v("点击 删除 按钮弹出删除确认窗口,如图所示。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_delete_1.png",alt:"manager_aggregate_delete_1"}})]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_delete_2.png",alt:"manager_aggregate_delete_2"}})]),a._v(" "),s("p",[a._v("点击 确定 按钮后删除接口,处于已发布状态的接口无法删除,需要下线后才能操作删除。")]),a._v(" "),s("h2",{attrs:{id:"发布-下线申请"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#发布-下线申请"}},[a._v("#")]),a._v(" 发布|下线申请")]),a._v(" "),s("p",[a._v("发布|下线申请用于聚合接口的发布或者下线申请,只有通过审核人审核后申请人才能执行发布|下线操作,避免误操作‘,保证接口的安全。")]),a._v(" "),s("p",[a._v("点击 发布|下线申请 按钮,弹出发布|下线申请窗口,如图所示。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_apply_1.png",alt:"manager_aggregate_apply_1"}})]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_apply_2.png",alt:"manager_aggregate_apply_2"}})]),a._v(" "),s("p",[a._v("点击 添加 按钮后,弹出接口列表,勾选需要操作的接口,点击 确定 添加进申请中。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_apply_3.png",alt:"manager_aggregate_apply_3"}})]),a._v(" "),s("p",[a._v("标题:申请的标题,长度不能超过200个字符,必填;")]),a._v(" "),s("p",[a._v("类型:申请类型,可选发布|下线,必选;")]),a._v(" "),s("p",[a._v("申请原因:申请的原因,长度不能超过2000个字符;")]),a._v(" "),s("p",[a._v("选择审核人:选择有审核权限的人对申请进行审核,列表根据需要操作的接口动态变化(未添加接口时列表为空,拥有服务权限并且有待审核菜单权限的人、操作管理员角色的人为可选审核人),必选;")]),a._v(" "),s("p",[a._v("点击 确定 按钮后提交申请,选择的审核人会收到申请审核邮件(审核人邮箱地址通过用户管理设置,更多详情请查看用户管理功能介绍),如图所示。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_apply_4.png",alt:"manager_aggregate_apply_4"}})]),a._v(" "),s("h2",{attrs:{id:"接口测试"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#接口测试"}},[a._v("#")]),a._v(" 接口测试")]),a._v(" "),s("p",[a._v("后台提供了可视化的接口调用界面,聚合接口创建完成后可通过该界面对接口进行调用测试。通过点击接口详情页面的 测试 按钮打开接口测试页面,如图所示。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_test_1.png",alt:"manager_aggregate_test_1"}})]),a._v(" "),s("p",[a._v("跳转页面的同时后台会将接口当前的最新配置推送给Fizz网关生成一个测试接口,请求路径为/proxytest/{service}/{apiPath}。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_test_2.png",alt:"manager_aggregate_test_2"}})]),a._v(" "),s("p",[a._v("点击 发送 按钮向指定接口发送一次请求,Response响应结果区域显示调用接口结果,如图所示。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_test_3.png",alt:"manager_aggregate_test_3"}})]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_test_4.png",alt:"manager_aggregate_test_4"}})]),a._v(" "),s("p",[a._v("请求体tab用于配置请求的请求体参数。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_test_5.png",alt:"manager_aggregate_test_5"}})]),a._v(" "),s("p",[a._v("请求头tab用于配置请求的请求头参数。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_test_6.png",alt:"manager_aggregate_test_6"}})]),a._v(" "),s("p",[a._v("Query参数用于配置请求的Query参数。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_test_7.png",alt:"manager_aggregate_test_7"}})]),a._v(" "),s("p",[a._v("返回Context:Fizz网关中一次聚合接口的请求过程中内部会持有一个Context对象,该对象保存了本次请求过程的入参信息、底层服务接口调用信息、响应信息,通过勾选该选项,接口会将Context随接口响应一起返回,通过查看Context可以清楚地了解接口的实际调用过程。")]),a._v(" "),s("p",[a._v("未勾选 返回Context 选项时,接口按配置输出的设置响应结果,如图所示。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_test_8.png",alt:"manager_aggregate_test_8"}})]),a._v(" "),s("p",[a._v("勾选 返回Context 选项后,接口会将Context随接口响应一起返回,如图所示。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_test_9.png",alt:"manager_aggregate_test_9"}})]),a._v(" "),s("p",[a._v("测试接口:调用测试接口,请求路径为/proxytest/{service}/{apiPath};")]),a._v(" "),s("p",[a._v("正式接口:调用正式接口,请求路径为/proxy/{service}/{apiPath};")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_test_10.png",alt:"manager_aggregate_test_10"}})]),a._v(" "),s("p",[a._v("点击 保存 按钮会将本次测试请求数据保存下来,通过选取已保存的测试记录可以快速恢复请求数据,如图所示。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_test_11.png",alt:"manager_aggregate_test_11"}})]),a._v(" "),s("p",[a._v("标题:本次测试数据保存时使用的标题,长度不能超过2000个字符,保存后在历史测试记录列表显示,如图所示。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_test_12.png",alt:"manager_aggregate_test_12"}})])])}),[],!1,null,null,null);t.default=e.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[14],{363:function(a,t,s){"use strict";s.r(t);var r=s(42),e=Object(r.a)({},(function(){var a=this,t=a.$createElement,s=a._self._c||t;return s("ContentSlotsDistributor",{attrs:{"slot-key":a.$parent.slotKey}},[s("h2",{attrs:{id:"概述"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#概述"}},[a._v("#")]),a._v(" 概述")]),a._v(" "),s("p",[a._v("接口列表功能用于维护聚合接口,聚合接口从外部调用方角度看是一个简单的接口,通过入参请求获取响应结果,内部实现会调用多个底层后端服务,将多个调用结果聚合转换成外部调用方想要的数据格式,更多详情请查看服务编排介绍,下面介绍接口列表功能的操作。")]),a._v(" "),s("h2",{attrs:{id:"接口列表"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#接口列表"}},[a._v("#")]),a._v(" 接口列表")]),a._v(" "),s("p",[a._v("菜单位置:服务编排 > 接口列表。点击菜单后进入接口列表页面,如图所示。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_list_query.png",alt:"manager_aggregate_list_query"}})]),a._v(" "),s("h2",{attrs:{id:"新增接口"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#新增接口"}},[a._v("#")]),a._v(" 新增接口")]),a._v(" "),s("p",[a._v("点击 新增 按钮弹出新增窗口,如图所示。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_add_1.png",alt:"manager_aggregate_add_1"}})]),a._v(" "),s("h3",{attrs:{id:"基础信息"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#基础信息"}},[a._v("#")]),a._v(" 基础信息")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_add_2.png",alt:"manager_aggregate_add_2"}})]),a._v(" "),s("p",[a._v("所属服务:接口所属服务,更多详情请查看服务管理功能介绍,必选;")]),a._v(" "),s("p",[a._v("接口名:接口名称,用于展示使用,长度不能超过200个字符,必填;")]),a._v(" "),s("p",[a._v("方法:接口请求方法类型,可选GET|POST,必选;")]),a._v(" "),s("p",[a._v("路径:接口请求路径后缀,长度不能超过2000个字符,必填;")]),a._v(" "),s("p",[a._v("开发人员:接口对应负责的开发人员,长度不能超过200个字符;")]),a._v(" "),s("p",[a._v("描述:接口功能描述,长度不能超过2000个字符;")]),a._v(" "),s("p",[a._v("举个例子,所属服务设置my-test-service,方法设置POST,路径设置test-aggregate-post,对应的聚合接口请求为 POST http://{Fizz网关ip地址}:{port端口}/proxy/my-test-service/test-aggregate-post。")]),a._v(" "),s("h3",{attrs:{id:"配置输入"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#配置输入"}},[a._v("#")]),a._v(" 配置输入")]),a._v(" "),s("p",[a._v("聚合接口的入参大部分是通过JSON Schema来定义的,下面先简单地介绍下JSON Schema。")]),a._v(" "),s("h4",{attrs:{id:"json-schema介绍"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#json-schema介绍"}},[a._v("#")]),a._v(" JSON Schema介绍")]),a._v(" "),s("p",[a._v("JSON Schema实际上也是JSON数据,用于标注和验证JSON文档,可以类比于XML Schema,当前最新版本2019-09。")]),a._v(" "),s("p",[a._v("作为普通用户,我们并不需要去了解JSON Schema的规范内容,只要能够构建JSON Schema即可。")]),a._v(" "),s("blockquote",[s("p",[a._v("要理解JSON Schema,首先要理解什么是JSON。JSON是JavaScript Object Notation的缩写,一种简单的数据交换格式。最初JSON是基于JavaScript,广泛的应用于万维网。由于其简洁和清晰的层次结构、易于人阅读等特性,使得越来越多的场景下被采用。")]),a._v(" "),s("p",[a._v("JSON包含以下数据结构:")]),a._v(" "),s("ul",[s("li",[a._v("object:"),s("div",{staticClass:"language-javascript extra-class"},[s("pre",{pre:!0,attrs:{class:"language-javascript"}},[s("code",[s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"key1"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"value1"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"key2"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"value2"')]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),a._v("\n")])])])]),a._v(" "),s("li",[a._v("array:"),s("div",{staticClass:"language-javascript extra-class"},[s("pre",{pre:!0,attrs:{class:"language-javascript"}},[s("code",[s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("[")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"first"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"second"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"third"')]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("]")]),a._v("\n")])])])]),a._v(" "),s("li",[a._v("number:"),s("div",{staticClass:"language-javascript extra-class"},[s("pre",{pre:!0,attrs:{class:"language-javascript"}},[s("code",[s("span",{pre:!0,attrs:{class:"token number"}},[a._v("42")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token number"}},[a._v("3.1415926")]),a._v("\n")])])])]),a._v(" "),s("li",[a._v("string:"),s("div",{staticClass:"language-javascript extra-class"},[s("pre",{pre:!0,attrs:{class:"language-javascript"}},[s("code",[s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"This is a string"')]),a._v("\n")])])])]),a._v(" "),s("li",[a._v("boolean:"),s("div",{staticClass:"language-javascript extra-class"},[s("pre",{pre:!0,attrs:{class:"language-javascript"}},[s("code",[s("span",{pre:!0,attrs:{class:"token boolean"}},[a._v("true")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token boolean"}},[a._v("false")]),a._v("\n")])])])]),a._v(" "),s("li",[a._v("null:"),s("div",{staticClass:"language-javascript extra-class"},[s("pre",{pre:!0,attrs:{class:"language-javascript"}},[s("code",[s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("null")]),a._v("\n")])])])])]),a._v(" "),s("p",[a._v("通过以上的简单数据类型,就能构造复杂的结构化数据了。下面举两个例子:")]),a._v(" "),s("div",{staticClass:"language-javascript extra-class"},[s("pre",{pre:!0,attrs:{class:"language-javascript"}},[s("code",[s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"name"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"George Washington"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"birthday"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"February 22, 1732"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"address"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"Mount Vernon, Virginia, United States"')]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),a._v("\n")])])]),s("div",{staticClass:"language-javascript extra-class"},[s("pre",{pre:!0,attrs:{class:"language-javascript"}},[s("code",[s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"first_name"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"George"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"last_name"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"Washington"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"birthday"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"1732-02-22"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"address"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"street_address"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"3200 Mount Vernon Memorial Highway"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"city"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"Mount Vernon"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"state"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"Virginia"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"country"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"United States"')]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),a._v("\n")])])]),s("p",[a._v("以上两个例子都是有效的JSON数据,包含一样的有效信息,但是当程序读取数据时,需要准确的知道数据是怎么组织的,比如哪些字段是必须,这些字段是什么类型。这时候JSON Schema就派上用场了,看以下JSON Schema例子:")]),a._v(" "),s("div",{staticClass:"language-javascript extra-class"},[s("pre",{pre:!0,attrs:{class:"language-javascript"}},[s("code",[s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"type"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"object"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"properties"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"first_name"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"type"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"string"')]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"last_name"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"type"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"string"')]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"birthday"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"type"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"string"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"format"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"date"')]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"address"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"type"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"object"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"properties"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"street_address"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"type"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"string"')]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"city"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"type"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"string"')]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"state"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"type"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"string"')]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"country"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"type"')]),a._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"string"')]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),a._v("\n")])])]),s("p",[a._v("用以上JSON Schema验证第一个例子时,验证失败;但是第二个例子验证通过。")]),a._v(" "),s("p",[a._v("JSON Schema本身也是通过JSON编写,其本身也是数据,不是一个计算机程序,只是一种“描述其它数据的结构”的声明格式。这既是长处,也是弱点,JSON Schema可以简洁地描述数据的结构并且自动验证数据,但是对于数据元素间的关系表达就力不能及了。")])]),a._v(" "),s("p",[a._v("更多JSON Schema知识可以阅读"),s("a",{attrs:{href:"https://json-schema.org/understanding-json-schema/",target:"_blank",rel:"noopener noreferrer"}},[a._v("Understanding JSON Schema"),s("OutboundLink")],1),a._v("。")]),a._v(" "),s("h4",{attrs:{id:"请求头部"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#请求头部"}},[a._v("#")]),a._v(" 请求头部")]),a._v(" "),s("p",[a._v("定义聚合接口的请求Header参数。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_add_3.png",alt:"manager_aggregate_add_3"}})]),a._v(" "),s("p",[a._v("举个例子:")]),a._v(" "),s("div",{staticClass:"language-javascript extra-class"},[s("pre",{pre:!0,attrs:{class:"language-javascript"}},[s("code",[s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"type"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"object"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"properties"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"headerParam1"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"type"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"string"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"title"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"请求头参数1"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"titleEn"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"headerParam1"')]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"required"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("[")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"headerParam1"')]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("]")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),a._v("\n")])])]),s("p",[a._v("以上例子定义了必传请求头参数"),s("code",[a._v("headerParam1")]),a._v("。")]),a._v(" "),s("p",[s("code",[a._v("title")]),a._v("字段用于验证失败时提示使用,例如请求接口时没传请求头时会提示“请求头参数1不能为空”(错误提示输出通过校验结果配置,详情请看后文介绍),如图所示。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_add_input_header_1.png",alt:"manager_aggregate_add_input_header_1"}})]),a._v(" "),s("p",[a._v("当定义了语言配置(详情请查看后文的语言配置介绍)选项为英文时会使用"),s("code",[a._v("titleEn")]),a._v("字段用于验证失败时提示使用,例如请求接口时没传请求头时会提示“headerParam1 is missing but it is required”(错误提示输出通过校验结果配置,详情请看后文介绍),如图所示。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_add_input_header_2.png",alt:"manager_aggregate_add_input_header_2"}})]),a._v(" "),s("h4",{attrs:{id:"请求体"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#请求体"}},[a._v("#")]),a._v(" 请求体")]),a._v(" "),s("p",[a._v("定义聚合接口的请求体参数。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_add_4.png",alt:"manager_aggregate_add_4"}})]),a._v(" "),s("p",[a._v("举个例子:")]),a._v(" "),s("div",{staticClass:"language-javascript extra-class"},[s("pre",{pre:!0,attrs:{class:"language-javascript"}},[s("code",[s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"type"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"object"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"properties"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"bodyParam1"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"type"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"string"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"title"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"请求体参数1"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"titleEn"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"bodyParam1"')]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"required"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("[")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"bodyParam1"')]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("]")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),a._v("\n")])])]),s("p",[a._v("以上例子定义了必传请求体参数"),s("code",[a._v("bodyParam1")]),a._v("。")]),a._v(" "),s("p",[s("code",[a._v("title")]),a._v("字段用于验证失败时提示使用,例如请求接口时没传请求体参数时会提示“请求体参数1不能为空”(错误提示输出通过校验结果配置,详情请看后文介绍),如图所示。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_add_input_body_1.png",alt:"manager_aggregate_add_input_body_1"}})]),a._v(" "),s("p",[a._v("当定义了语言配置(详情请查看后文的语言配置介绍)选项为英文时会使用"),s("code",[a._v("titleEn")]),a._v("字段用于验证失败时提示使用,例如请求接口时没传请求体参数时会提示“bodyParam1 is missing but it is required”(错误提示输出通过校验结果配置,详情请看后文介绍),如图所示。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_add_input_body_2.png",alt:"manager_aggregate_add_input_body_2"}})]),a._v(" "),s("h4",{attrs:{id:"query参数"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#query参数"}},[a._v("#")]),a._v(" Query参数")]),a._v(" "),s("p",[a._v("定义聚合接口的Query参数。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_add_5.png",alt:"manager_aggregate_add_5"}})]),a._v(" "),s("p",[a._v("举个例子:")]),a._v(" "),s("div",{staticClass:"language-javascript extra-class"},[s("pre",{pre:!0,attrs:{class:"language-javascript"}},[s("code",[s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"type"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"object"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"properties"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"queryParam1"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"type"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"string"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"title"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"query参数1"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"titleEn"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"queryParam1"')]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"required"')]),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v(":")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("[")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"queryParam1"')]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("]")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),a._v("\n")])])]),s("p",[a._v("以上例子定义了必传Query参数"),s("code",[a._v("queryParam1")]),a._v("。")]),a._v(" "),s("p",[s("code",[a._v("title")]),a._v("字段用于验证失败时提示使用,例如请求接口时没传Query参数时会提示“query参数1不能为空”(错误提示输出通过校验结果配置,详情请看后文介绍),如图所示。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_add_input_query_1.png",alt:"manager_aggregate_add_input_query_1"}})]),a._v(" "),s("p",[a._v("当定义了语言配置(详情请查看后文的语言配置介绍)选项为英文时会使用"),s("code",[a._v("titleEn")]),a._v("字段用于验证失败时提示使用,例如请求接口时没传Query参数时会提示“queryParam1 is missing but it is required”(错误提示输出通过校验结果配置,详情请看后文介绍),如图所示。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_add_input_query_2.png",alt:"manager_aggregate_add_input_query_2"}})]),a._v(" "),s("h4",{attrs:{id:"脚本校验"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#脚本校验"}},[a._v("#")]),a._v(" 脚本校验")]),a._v(" "),s("p",[a._v("对于JSON Schema规范无法覆盖的校验场景可以使用脚本对入参进行更加灵活的处理。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_add_6.png",alt:"manager_aggregate_add_6"}})]),a._v(" "),s("p",[a._v("点击 新增 按钮后弹出脚本配置窗口,如图所示。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_add_7.png",alt:"manager_aggregate_add_7"}})]),a._v(" "),s("p",[a._v("脚本类型:可选javascript|groovy,必选;")]),a._v(" "),s("p",[a._v("脚本内容:所选的脚本类型语言编写的入参验证脚本,必填。")]),a._v(" "),s("p",[a._v("举个例子:")]),a._v(" "),s("div",{staticClass:"language-javascript extra-class"},[s("pre",{pre:!0,attrs:{class:"language-javascript"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[a._v("// javascript脚本函数名不能修改")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("function")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("dyFunc")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token parameter"}},[a._v("paramsJsonStr")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[a._v("// 上下文, 数据结构请参考 context.js")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("var")]),a._v(" context "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token constant"}},[a._v("JSON")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("parse")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),a._v("paramsJsonStr"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[a._v("'context'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[a._v("// common为内置的上下文便捷操作工具类,详情请参考common.js;例如:")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[a._v("// var data = common.getStepRespBody(context, 'step2', 'request1', 'data');")]),a._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[a._v("// do something")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("var")]),a._v(" headerParam1 "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v(" common"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("getInputReqHeader")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),a._v("context"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v("'headerParam1'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("var")]),a._v(" bodyParam1 "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v(" common"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("getInputReqBody")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),a._v("context"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v("'bodyParam1'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("var")]),a._v(" queryParam1 "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v(" common"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("getInputReqParam")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),a._v("context"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[a._v("'queryParam1'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("var")]),a._v(" result "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("=")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("new")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[a._v("Array")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("if")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),a._v("headerParam1 "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("!=")]),a._v(" bodyParam1"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n result"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("push")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"headerParam1与bodyParam1不一致"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("if")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),a._v("queryParam1 "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("!=")]),a._v(" bodyParam1"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n result"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("push")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"queryParam1与bodyParam1不一致"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("if")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),a._v("headerParam1 "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("!=")]),a._v(" queryParam1"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n result"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("push")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token string"}},[a._v('"headerParam1与queryParam1不一致"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),a._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[a._v("// 返回结果为Array或Object时要先转为json字符串")]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("return")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token constant"}},[a._v("JSON")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("stringify")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),a._v("result"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),a._v("\n\n")])])]),s("p",[a._v("以上例子使用javascript编写参数校验,限制入参"),s("code",[a._v("headerParam1")]),a._v("、"),s("code",[a._v("bodyParam1")]),a._v("、"),s("code",[a._v("queryParam1")]),a._v("必须一致,不一致将提示错误信息(错误提示输出通过校验结果配置,详情请看后文介绍),如图所示。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_add_input_script.png",alt:"manager_aggregate_add_input_script"}})]),a._v(" "),s("h4",{attrs:{id:"语言配置"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#语言配置"}},[a._v("#")]),a._v(" 语言配置")]),a._v(" "),s("p",[a._v("聚合接口默认使用中文响应校验失败提示,通过配置可通过入参选择不同的提示语言,目前支持中文、英文提示(已满足我们的业务使用场景,有其他语言要求的小伙伴可以联系我们添加)。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_add_8.png",alt:"manager_aggregate_add_8"}})]),a._v(" "),s("p",[a._v("字段:入参字段值,例如"),s("code",[a._v("input.request.body.languageCode")]),a._v("使用请求体参数"),s("code",[a._v("languageCode")]),a._v("的值来决定使用哪种语言;")]),a._v(" "),s("p",[a._v("中文:中文与入参字段值的映射关系,例如配置"),s("code",[a._v("0")]),a._v(",当请求入参字段值为"),s("code",[a._v("0")]),a._v("时使用中文提示校验结果;")]),a._v(" "),s("p",[a._v("英文:英文与入参字段值的映射关系,例如配置"),s("code",[a._v("1")]),a._v(",当请求入参字段值为"),s("code",[a._v("1")]),a._v("时使用中文提示校验结果。")]),a._v(" "),s("h3",{attrs:{id:"配置步骤"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#配置步骤"}},[a._v("#")]),a._v(" 配置步骤")]),a._v(" "),s("p",[a._v("聚合接口调用底层服务是通过多个step实现的,多个step串行执行,每个step包含多个request(对底层服务接口的调用),同个step里的多个request并行执行,后执行的step可以获取已执行step的执行结果,更多详情请查看服务编排文章的介绍,下面介绍配置步骤的使用。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_add_9.png",alt:"manager_aggregate_add_9"}})]),a._v(" "),s("p",[a._v("是否执行完此步骤后结束:勾选后实际请求只执行完该步骤后即响应结果,不执行后续步骤,用于调试使用;")]),a._v(" "),s("p",[a._v("请求方法:调用底层服务接口的请求类型,可选GET|POST,必选;")]),a._v(" "),s("p",[a._v("默认URL:调用底层服务接口的默认URL,当Fizz网关启动环境没有配置URL时使用该默认URL;")]),a._v(" "),s("p",[a._v("开发环境URL:开发环境调用底层服务接口的URL,当Fizz网关启动使用spring.profiles.active=dev时使用该URL;")]),a._v(" "),s("p",[a._v("测试环境URL:测试环境调用底层服务接口的URL,当Fizz网关启动使用spring.profiles.active=test时使用该URL;")]),a._v(" "),s("p",[a._v("预生产环境URL:预生产环境调用底层服务接口的URL,当Fizz网关启动使用spring.profiles.active=pre时使用该URL;")]),a._v(" "),s("p",[a._v("生产环境URL:生产环境调用底层服务接口的URL,当Fizz网关启动使用spring.profiles.active=prod时使用该URL;")]),a._v(" "),s("p",[a._v("超时时间(毫秒):调用底层服务接口的超时时间,超时抛出异常,单位毫秒;")]),a._v(" "),s("p",[a._v("Fallback:可选stop|continue,控制当调用底层服务接口失败后是否继续执行后续操作;")]),a._v(" "),s("p",[a._v("请求预处理:勾选后可配置预处理脚本,预处理脚本返回true时才执行调用底层服务接口。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_add_10.png",alt:"manager_aggregate_add_10"}})]),a._v(" "),s("p",[a._v("配置入参:配置调用底层服务接口的请求参数;")]),a._v(" "),s("p",[a._v("配置响应:配置调用底层服务接口的响应内容。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_add_11.png",alt:"manager_aggregate_add_11"}})]),a._v(" "),s("p",[a._v("配置步骤结果:配置step执行完成后的响应内容。")]),a._v(" "),s("h3",{attrs:{id:"配置输出"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#配置输出"}},[a._v("#")]),a._v(" 配置输出")]),a._v(" "),s("p",[a._v("配置聚合接口调用完成的响应内容。在响应体、响应头配置中可以配置简单的响应固定值、响应引用值,对于需要逻辑处理得到结果的响应可以通过脚本配置灵活处理,如图所示。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_add_12.png",alt:"manager_aggregate_add_12"}})]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_add_13.png",alt:"manager_aggregate_add_13"}})]),a._v(" "),s("h3",{attrs:{id:"校验结果"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#校验结果"}},[a._v("#")]),a._v(" 校验结果")]),a._v(" "),s("p",[a._v("配置聚合接口入参校验失败后的响应内容,在响应体、响应头配置中可以配置简单的响应固定值、响应引用值,对于需要逻辑处理得到结果的响应可以通过脚本配置灵活处理,如图所示。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_add_14.png",alt:"manager_aggregate_add_14"}})]),a._v(" "),s("p",[a._v("校验结果有一个专用的引用值"),s("code",[a._v("validateMsg")]),a._v(",该引用值用于存放入参验证错误提示信息。")]),a._v(" "),s("h3",{attrs:{id:"保存接口"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#保存接口"}},[a._v("#")]),a._v(" 保存接口")]),a._v(" "),s("p",[a._v("所有配置完成后点击 保存 按钮,完成聚合接口的配置。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_add_15.png",alt:"manager_aggregate_add_15"}})]),a._v(" "),s("h2",{attrs:{id:"导出接口"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#导出接口"}},[a._v("#")]),a._v(" 导出接口")]),a._v(" "),s("p",[a._v("导出功能将聚合接口以配置文件的形式导出,导出的文件可通过导入功能重新导入系统,当我们的系统分多个环境时,可使用导出导入功能实现聚合接口的快速同步,下面介绍导出功能。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_export_1.png",alt:"manager_aggregate_export_1"}})]),a._v(" "),s("p",[a._v("勾选想到导出的接口,点击 导出 按钮弹出确认窗口,如图所示。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_export_2.png",alt:"manager_aggregate_export_2"}})]),a._v(" "),s("p",[a._v("点击 确定 按钮,浏览器保存配置文件,如图所示。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_export_3.png",alt:"manager_aggregate_export_3"}})]),a._v(" "),s("h2",{attrs:{id:"导入接口"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#导入接口"}},[a._v("#")]),a._v(" 导入接口")]),a._v(" "),s("p",[a._v("导入功能将配置文件中的聚合接口转化成后台的持久化存储,导入的文件可以通过导出功能获取或者通过编写好的聚合配置JSON文件转化得到(转换工具可以联系我们获取)。当我们的系统分多个环境时,可使用导出导入功能实现聚合接口的快速同步,下面介绍导出功能。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_import_1.png",alt:"manager_aggregate_import_1"}})]),a._v(" "),s("p",[a._v("点击 导入 按钮弹出导入配置窗口,如图所示。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_import_2.png",alt:"manager_aggregate_import_2"}})]),a._v(" "),s("p",[a._v("点击 选取文件 按钮后选取要导入的配置文件;")]),a._v(" "),s("p",[a._v("强制覆盖:通过请求类型(GET|POST)、请求路径(/proxy/{service}/{apiPath})可以唯一确定一个聚合接口,当聚合接口已存在时,未勾选该选项时忽略该聚合接口导入,勾选该选项时覆盖已存在的聚合接口配置;")]),a._v(" "),s("p",[a._v("点击 确定 按钮后导入聚合接口配置。")]),a._v(" "),s("h2",{attrs:{id:"调试模式"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#调试模式"}},[a._v("#")]),a._v(" 调试模式")]),a._v(" "),s("p",[a._v("调试模式用于对接口开发过程中的调试使用,当打开调试模式后,Fizz网关会将聚合接口调用底层服务接口的请求响应信息以及耗时、聚合结果、步骤上下文打印到日志中,通过日志可以清楚的了解聚合接口的实际执行情况。调试模式会对网关性能造成影响,因此不建议在生产环境打开调试模式,当调试完成后及时关闭调试模式,避免打印过多日志造成资源浪费,下面介绍调试模式的使用。")]),a._v(" "),s("p",[a._v("勾选想要打开调试模式的接口,点击 打开调试模式 按钮弹出确认窗口,如图所示。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_debug_mode_1.png",alt:"manager_aggregate_debug_mode_1"}})]),a._v(" "),s("p",[a._v("点击 确定 按钮确认打开调试模式。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_debug_mode_2.png",alt:"manager_aggregate_debug_mode_2"}})]),a._v(" "),s("p",[a._v("勾选想要关闭调试模式的接口,点击 关闭调试模式 按钮弹出确认窗口,如图所示。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_debug_mode_3.png",alt:"manager_aggregate_debug_mode_3"}})]),a._v(" "),s("p",[a._v("点击 确定 按钮确认关闭调试模式。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_debug_mode_4.png",alt:"manager_aggregate_debug_mode_4"}})]),a._v(" "),s("h2",{attrs:{id:"编辑接口"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#编辑接口"}},[a._v("#")]),a._v(" 编辑接口")]),a._v(" "),s("p",[a._v("点击 编辑 按钮弹出编辑窗口,如图所示。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_edit_1.png",alt:"manager_aggregate_edit_1"}})]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_edit_2.png",alt:"manager_aggregate_edit_2"}})]),a._v(" "),s("h2",{attrs:{id:"删除接口"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#删除接口"}},[a._v("#")]),a._v(" 删除接口")]),a._v(" "),s("p",[a._v("点击 删除 按钮弹出删除确认窗口,如图所示。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_delete_1.png",alt:"manager_aggregate_delete_1"}})]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_delete_2.png",alt:"manager_aggregate_delete_2"}})]),a._v(" "),s("p",[a._v("点击 确定 按钮后删除接口,处于已发布状态的接口无法删除,需要下线后才能操作删除。")]),a._v(" "),s("h2",{attrs:{id:"发布-下线申请"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#发布-下线申请"}},[a._v("#")]),a._v(" 发布|下线申请")]),a._v(" "),s("p",[a._v("发布|下线申请用于聚合接口的发布或者下线申请,只有通过审核人审核后申请人才能执行发布|下线操作,避免误操作‘,保证接口的安全。")]),a._v(" "),s("p",[a._v("点击 发布|下线申请 按钮,弹出发布|下线申请窗口,如图所示。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_apply_1.png",alt:"manager_aggregate_apply_1"}})]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_apply_2.png",alt:"manager_aggregate_apply_2"}})]),a._v(" "),s("p",[a._v("点击 添加 按钮后,弹出接口列表,勾选需要操作的接口,点击 确定 添加进申请中。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_apply_3.png",alt:"manager_aggregate_apply_3"}})]),a._v(" "),s("p",[a._v("标题:申请的标题,长度不能超过200个字符,必填;")]),a._v(" "),s("p",[a._v("类型:申请类型,可选发布|下线,必选;")]),a._v(" "),s("p",[a._v("申请原因:申请的原因,长度不能超过2000个字符;")]),a._v(" "),s("p",[a._v("选择审核人:选择有审核权限的人对申请进行审核,列表根据需要操作的接口动态变化(未添加接口时列表为空,拥有服务权限并且有待审核菜单权限的人、操作管理员角色的人为可选审核人),必选;")]),a._v(" "),s("p",[a._v("点击 确定 按钮后提交申请,选择的审核人会收到申请审核邮件(审核人邮箱地址通过用户管理设置,更多详情请查看用户管理功能介绍),如图所示。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_apply_4.png",alt:"manager_aggregate_apply_4"}})]),a._v(" "),s("h2",{attrs:{id:"接口测试"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#接口测试"}},[a._v("#")]),a._v(" 接口测试")]),a._v(" "),s("p",[a._v("后台提供了可视化的接口调用界面,聚合接口创建完成后可通过该界面对接口进行调用测试。通过点击接口详情页面的 测试 按钮打开接口测试页面,如图所示。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_test_1.png",alt:"manager_aggregate_test_1"}})]),a._v(" "),s("p",[a._v("跳转页面的同时后台会将接口当前的最新配置推送给Fizz网关生成一个测试接口,请求路径为/proxytest/{service}/{apiPath}。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_test_2.png",alt:"manager_aggregate_test_2"}})]),a._v(" "),s("p",[a._v("点击 发送 按钮向指定接口发送一次请求,Response响应结果区域显示调用接口结果,如图所示。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_test_3.png",alt:"manager_aggregate_test_3"}})]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_test_4.png",alt:"manager_aggregate_test_4"}})]),a._v(" "),s("p",[a._v("请求体tab用于配置请求的请求体参数。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_test_5.png",alt:"manager_aggregate_test_5"}})]),a._v(" "),s("p",[a._v("请求头tab用于配置请求的请求头参数。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_test_6.png",alt:"manager_aggregate_test_6"}})]),a._v(" "),s("p",[a._v("Query参数用于配置请求的Query参数。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_test_7.png",alt:"manager_aggregate_test_7"}})]),a._v(" "),s("p",[a._v("返回Context:Fizz网关中一次聚合接口的请求过程中内部会持有一个Context对象,该对象保存了本次请求过程的入参信息、底层服务接口调用信息、响应信息,通过勾选该选项,接口会将Context随接口响应一起返回,通过查看Context可以清楚地了解接口的实际调用过程。")]),a._v(" "),s("p",[a._v("未勾选 返回Context 选项时,接口按配置输出的设置响应结果,如图所示。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_test_8.png",alt:"manager_aggregate_test_8"}})]),a._v(" "),s("p",[a._v("勾选 返回Context 选项后,接口会将Context随接口响应一起返回,如图所示。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_test_9.png",alt:"manager_aggregate_test_9"}})]),a._v(" "),s("p",[a._v("测试接口:调用测试接口,请求路径为/proxytest/{service}/{apiPath};")]),a._v(" "),s("p",[a._v("正式接口:调用正式接口,请求路径为/proxy/{service}/{apiPath};")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_test_10.png",alt:"manager_aggregate_test_10"}})]),a._v(" "),s("p",[a._v("点击 保存 按钮会将本次测试请求数据保存下来,通过选取已保存的测试记录可以快速恢复请求数据,如图所示。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_test_11.png",alt:"manager_aggregate_test_11"}})]),a._v(" "),s("p",[a._v("标题:本次测试数据保存时使用的标题,长度不能超过2000个字符,保存后在历史测试记录列表显示,如图所示。")]),a._v(" "),s("p",[s("img",{attrs:{src:"/manager_aggregate_test_12.png",alt:"manager_aggregate_test_12"}})])])}),[],!1,null,null,null);t.default=e.exports}}]); \ No newline at end of file diff --git a/docs/assets/js/15.0358b10e.js b/docs/assets/js/15.791d6b9d.js similarity index 96% rename from docs/assets/js/15.0358b10e.js rename to docs/assets/js/15.791d6b9d.js index 75de6b9..00c65dc 100644 --- a/docs/assets/js/15.0358b10e.js +++ b/docs/assets/js/15.791d6b9d.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[15],{359:function(a,r,t){"use strict";t.r(r);var e=t(42),_=Object(e.a)({},(function(){var a=this,r=a.$createElement,t=a._self._c||r;return t("ContentSlotsDistributor",{attrs:{"slot-key":a.$parent.slotKey}},[t("h2",{attrs:{id:"概述"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#概述"}},[a._v("#")]),a._v(" 概述")]),a._v(" "),t("p",[a._v("聚合接口的发布|下线操作需要提交发布|下线申请,审核通过后申请人才能执行发布|下线操作。待审核功能用于审核发布|下线申请,下面介绍待审核功能。")]),a._v(" "),t("h2",{attrs:{id:"审核列表"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#审核列表"}},[a._v("#")]),a._v(" 审核列表")]),a._v(" "),t("p",[a._v("菜单位置:发布申请 > 待审核。点击菜单后进入审核列表页面,如图所示。")]),a._v(" "),t("p",[t("img",{attrs:{src:"/manager_aggregate_approve_list_query.png",alt:"manager_aggregate_approve_list_query"}})]),a._v(" "),t("h2",{attrs:{id:"审核操作"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#审核操作"}},[a._v("#")]),a._v(" 审核操作")]),a._v(" "),t("p",[a._v("点击 查看 按钮可以查看发布|下线申请详情,详情页中可执行审核操作。")]),a._v(" "),t("p",[a._v("申请列表页提供快速审核操作,点击 审核 按钮后弹出审核确认窗口,如图所示。")]),a._v(" "),t("p",[t("img",{attrs:{src:"/manager_aggregate_approve_op_1.png",alt:"manager_aggregate_approve_op_1"}})]),a._v(" "),t("p",[t("img",{attrs:{src:"/manager_aggregate_approve_op_2.png",alt:"manager_aggregate_approve_op_2"}})]),a._v(" "),t("p",[a._v("审核结果:勾选通过,审核后申请能可执行申请的操作;勾选不通过,审核后申请失败,申请人不能执行申请的操作。")]),a._v(" "),t("p",[a._v("审核后申请人会收到审核结果邮件通知,如下图是审核通过的邮件通知。")]),a._v(" "),t("p",[t("img",{attrs:{src:"/manager_aggregate_approve_op_3.png",alt:"manager_aggregate_approve_op_3"}})])])}),[],!1,null,null,null);r.default=_.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[15],{360:function(a,r,t){"use strict";t.r(r);var e=t(42),_=Object(e.a)({},(function(){var a=this,r=a.$createElement,t=a._self._c||r;return t("ContentSlotsDistributor",{attrs:{"slot-key":a.$parent.slotKey}},[t("h2",{attrs:{id:"概述"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#概述"}},[a._v("#")]),a._v(" 概述")]),a._v(" "),t("p",[a._v("聚合接口的发布|下线操作需要提交发布|下线申请,审核通过后申请人才能执行发布|下线操作。待审核功能用于审核发布|下线申请,下面介绍待审核功能。")]),a._v(" "),t("h2",{attrs:{id:"审核列表"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#审核列表"}},[a._v("#")]),a._v(" 审核列表")]),a._v(" "),t("p",[a._v("菜单位置:发布申请 > 待审核。点击菜单后进入审核列表页面,如图所示。")]),a._v(" "),t("p",[t("img",{attrs:{src:"/manager_aggregate_approve_list_query.png",alt:"manager_aggregate_approve_list_query"}})]),a._v(" "),t("h2",{attrs:{id:"审核操作"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#审核操作"}},[a._v("#")]),a._v(" 审核操作")]),a._v(" "),t("p",[a._v("点击 查看 按钮可以查看发布|下线申请详情,详情页中可执行审核操作。")]),a._v(" "),t("p",[a._v("申请列表页提供快速审核操作,点击 审核 按钮后弹出审核确认窗口,如图所示。")]),a._v(" "),t("p",[t("img",{attrs:{src:"/manager_aggregate_approve_op_1.png",alt:"manager_aggregate_approve_op_1"}})]),a._v(" "),t("p",[t("img",{attrs:{src:"/manager_aggregate_approve_op_2.png",alt:"manager_aggregate_approve_op_2"}})]),a._v(" "),t("p",[a._v("审核结果:勾选通过,审核后申请能可执行申请的操作;勾选不通过,审核后申请失败,申请人不能执行申请的操作。")]),a._v(" "),t("p",[a._v("审核后申请人会收到审核结果邮件通知,如下图是审核通过的邮件通知。")]),a._v(" "),t("p",[t("img",{attrs:{src:"/manager_aggregate_approve_op_3.png",alt:"manager_aggregate_approve_op_3"}})])])}),[],!1,null,null,null);r.default=_.exports}}]); \ No newline at end of file diff --git a/docs/assets/js/16.43a475d2.js b/docs/assets/js/16.4ae255f1.js similarity index 95% rename from docs/assets/js/16.43a475d2.js rename to docs/assets/js/16.4ae255f1.js index 3337d04..3542d1e 100644 --- a/docs/assets/js/16.43a475d2.js +++ b/docs/assets/js/16.4ae255f1.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[16],{363:function(a,t,e){"use strict";e.r(t);var _=e(42),r=Object(_.a)({},(function(){var a=this,t=a.$createElement,e=a._self._c||t;return e("ContentSlotsDistributor",{attrs:{"slot-key":a.$parent.slotKey}},[e("h2",{attrs:{id:"概述"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#概述"}},[a._v("#")]),a._v(" 概述")]),a._v(" "),e("p",[a._v("管理后台记录了发布|下线申请的审核操作日志,审核日志功能提供界面查询后台记录的审核操作日志。")]),a._v(" "),e("h2",{attrs:{id:"审核日志列表"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#审核日志列表"}},[a._v("#")]),a._v(" 审核日志列表")]),a._v(" "),e("p",[a._v("菜单位置:发布申请 > 审核日志。点击菜单后进入审核日志列表页面,如图所示。")]),a._v(" "),e("p",[e("img",{attrs:{src:"/manager_aggregate_approve_op_log_list_query.png",alt:"manager_aggregate_approve_op_log_list_query"}})]),a._v(" "),e("h2",{attrs:{id:"审核日志详情"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#审核日志详情"}},[a._v("#")]),a._v(" 审核日志详情")]),a._v(" "),e("p",[a._v("点击 查看 按钮弹出审核日志详情页面,如图所示。")]),a._v(" "),e("p",[e("img",{attrs:{src:"/manager_aggregate_approve_op_log_detail_1.png",alt:"manager_aggregate_approve_op_log_detail_1"}})]),a._v(" "),e("p",[e("img",{attrs:{src:"/manager_aggregate_approve_op_log_detail_2.png",alt:"manager_aggregate_approve_op_log_detail_2"}})])])}),[],!1,null,null,null);t.default=r.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[16],{358:function(a,t,e){"use strict";e.r(t);var _=e(42),r=Object(_.a)({},(function(){var a=this,t=a.$createElement,e=a._self._c||t;return e("ContentSlotsDistributor",{attrs:{"slot-key":a.$parent.slotKey}},[e("h2",{attrs:{id:"概述"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#概述"}},[a._v("#")]),a._v(" 概述")]),a._v(" "),e("p",[a._v("管理后台记录了发布|下线申请的审核操作日志,审核日志功能提供界面查询后台记录的审核操作日志。")]),a._v(" "),e("h2",{attrs:{id:"审核日志列表"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#审核日志列表"}},[a._v("#")]),a._v(" 审核日志列表")]),a._v(" "),e("p",[a._v("菜单位置:发布申请 > 审核日志。点击菜单后进入审核日志列表页面,如图所示。")]),a._v(" "),e("p",[e("img",{attrs:{src:"/manager_aggregate_approve_op_log_list_query.png",alt:"manager_aggregate_approve_op_log_list_query"}})]),a._v(" "),e("h2",{attrs:{id:"审核日志详情"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#审核日志详情"}},[a._v("#")]),a._v(" 审核日志详情")]),a._v(" "),e("p",[a._v("点击 查看 按钮弹出审核日志详情页面,如图所示。")]),a._v(" "),e("p",[e("img",{attrs:{src:"/manager_aggregate_approve_op_log_detail_1.png",alt:"manager_aggregate_approve_op_log_detail_1"}})]),a._v(" "),e("p",[e("img",{attrs:{src:"/manager_aggregate_approve_op_log_detail_2.png",alt:"manager_aggregate_approve_op_log_detail_2"}})])])}),[],!1,null,null,null);t.default=r.exports}}]); \ No newline at end of file diff --git a/docs/assets/js/21.dca6f5c4.js b/docs/assets/js/21.081e4e30.js similarity index 97% rename from docs/assets/js/21.dca6f5c4.js rename to docs/assets/js/21.081e4e30.js index d131c88..60dba6b 100644 --- a/docs/assets/js/21.dca6f5c4.js +++ b/docs/assets/js/21.081e4e30.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[21],{367:function(a,e,t){"use strict";t.r(e);var _=t(42),r=Object(_.a)({},(function(){var a=this,e=a.$createElement,t=a._self._c||e;return t("ContentSlotsDistributor",{attrs:{"slot-key":a.$parent.slotKey}},[t("h2",{attrs:{id:"概述"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#概述"}},[a._v("#")]),a._v(" 概述")]),a._v(" "),t("p",[a._v("网关缓存功能用于查询Fizz网关实例本地缓存的已发布接口信息,可以快速的了解当前网关实例生效的全部接口,同时通过查看后台接口发布版本号与网关实例本地缓存的接口版本号是否一致可以排查接口缓存问题,下面介绍网关缓存功能的操作。")]),a._v(" "),t("h2",{attrs:{id:"网关列表"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#网关列表"}},[a._v("#")]),a._v(" 网关列表")]),a._v(" "),t("p",[a._v("菜单位置:服务编排 > 网关缓存。点击菜单后进入网关列表页面,如图所示。")]),a._v(" "),t("p",[t("img",{attrs:{src:"/manager_aggregate_gateway_list_query.png",alt:"manager_aggregate_gateway_list_query"}})]),a._v(" "),t("p",[a._v("Fizz网关与后台注册到同一个eureka注册中心,后台通过eureka获取网关的实例列表。")]),a._v(" "),t("h2",{attrs:{id:"网关缓存列表"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#网关缓存列表"}},[a._v("#")]),a._v(" 网关缓存列表")]),a._v(" "),t("p",[a._v("点击 查看 按钮后弹出网关详情页面,该页面显示所选网关实例的接口缓存列表,如图所示。")]),a._v(" "),t("p",[t("img",{attrs:{src:"/manager_aggregate_gateway_cache_list_query_1.png",alt:"manager_aggregate_gateway_cache_list_query_1"}})]),a._v(" "),t("p",[t("img",{attrs:{src:"/manager_aggregate_gateway_cache_list_query_2.png",alt:"manager_aggregate_gateway_cache_list_query_2"}})]),a._v(" "),t("h2",{attrs:{id:"网关缓存详情"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#网关缓存详情"}},[a._v("#")]),a._v(" 网关缓存详情")]),a._v(" "),t("p",[a._v("点击 查看 按钮弹出所选接口的配置详情,如图所示。")]),a._v(" "),t("p",[t("img",{attrs:{src:"/manager_aggregate_gateway_cache_detail_1.png",alt:"manager_aggregate_gateway_cache_detail_1"}})]),a._v(" "),t("p",[t("img",{attrs:{src:"/manager_aggregate_gateway_cache_detail_2.png",alt:"manager_aggregate_gateway_cache_detail_2"}})])])}),[],!1,null,null,null);e.default=r.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[21],{368:function(a,e,t){"use strict";t.r(e);var _=t(42),r=Object(_.a)({},(function(){var a=this,e=a.$createElement,t=a._self._c||e;return t("ContentSlotsDistributor",{attrs:{"slot-key":a.$parent.slotKey}},[t("h2",{attrs:{id:"概述"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#概述"}},[a._v("#")]),a._v(" 概述")]),a._v(" "),t("p",[a._v("网关缓存功能用于查询Fizz网关实例本地缓存的已发布接口信息,可以快速的了解当前网关实例生效的全部接口,同时通过查看后台接口发布版本号与网关实例本地缓存的接口版本号是否一致可以排查接口缓存问题,下面介绍网关缓存功能的操作。")]),a._v(" "),t("h2",{attrs:{id:"网关列表"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#网关列表"}},[a._v("#")]),a._v(" 网关列表")]),a._v(" "),t("p",[a._v("菜单位置:服务编排 > 网关缓存。点击菜单后进入网关列表页面,如图所示。")]),a._v(" "),t("p",[t("img",{attrs:{src:"/manager_aggregate_gateway_list_query.png",alt:"manager_aggregate_gateway_list_query"}})]),a._v(" "),t("p",[a._v("Fizz网关与后台注册到同一个eureka注册中心,后台通过eureka获取网关的实例列表。")]),a._v(" "),t("h2",{attrs:{id:"网关缓存列表"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#网关缓存列表"}},[a._v("#")]),a._v(" 网关缓存列表")]),a._v(" "),t("p",[a._v("点击 查看 按钮后弹出网关详情页面,该页面显示所选网关实例的接口缓存列表,如图所示。")]),a._v(" "),t("p",[t("img",{attrs:{src:"/manager_aggregate_gateway_cache_list_query_1.png",alt:"manager_aggregate_gateway_cache_list_query_1"}})]),a._v(" "),t("p",[t("img",{attrs:{src:"/manager_aggregate_gateway_cache_list_query_2.png",alt:"manager_aggregate_gateway_cache_list_query_2"}})]),a._v(" "),t("h2",{attrs:{id:"网关缓存详情"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#网关缓存详情"}},[a._v("#")]),a._v(" 网关缓存详情")]),a._v(" "),t("p",[a._v("点击 查看 按钮弹出所选接口的配置详情,如图所示。")]),a._v(" "),t("p",[t("img",{attrs:{src:"/manager_aggregate_gateway_cache_detail_1.png",alt:"manager_aggregate_gateway_cache_detail_1"}})]),a._v(" "),t("p",[t("img",{attrs:{src:"/manager_aggregate_gateway_cache_detail_2.png",alt:"manager_aggregate_gateway_cache_detail_2"}})])])}),[],!1,null,null,null);e.default=r.exports}}]); \ No newline at end of file diff --git a/docs/assets/js/22.db62cc12.js b/docs/assets/js/22.0c08546e.js similarity index 98% rename from docs/assets/js/22.db62cc12.js rename to docs/assets/js/22.0c08546e.js index 60bd5b1..7325cbd 100644 --- a/docs/assets/js/22.db62cc12.js +++ b/docs/assets/js/22.0c08546e.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[22],{368:function(_,a,t){"use strict";t.r(a);var r=t(42),e=Object(r.a)({},(function(){var _=this,a=_.$createElement,t=_._self._c||a;return t("ContentSlotsDistributor",{attrs:{"slot-key":_.$parent.slotKey}},[t("h2",{attrs:{id:"概述"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#概述"}},[_._v("#")]),_._v(" 概述")]),_._v(" "),t("p",[_._v("网关分组功能用于维护分组元数据,将网关实例IP与分组关联,通过为不同的分组配置不同的路由策略,从而实现网关的分组管理。")]),_._v(" "),t("h2",{attrs:{id:"分组示例"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#分组示例"}},[_._v("#")]),_._v(" 分组示例")]),_._v(" "),t("p",[_._v("我们的线上业务涉及To C(个人用户)、To B(企业)、To T(第三方),对于不同业务会有对应的机器接受请求访问,不同的业务需要有各自的路由策略,因此进行了如下的分组划分。")]),_._v(" "),t("table",[t("thead",[t("tr",[t("th",[_._v("分组ID")]),_._v(" "),t("th",[_._v("分组名称")]),_._v(" "),t("th",[_._v("描述")])])]),_._v(" "),t("tbody",[t("tr",[t("td",[_._v("default")]),_._v(" "),t("td",[_._v("默认分组")]),_._v(" "),t("td",[_._v("默认分组是后台默认创建的分组,不用指定IP,不属于其它分组的机器都归到默认分组,默认分组不可修改或删除")])]),_._v(" "),t("tr",[t("td",[_._v("c")]),_._v(" "),t("td",[_._v("2c分组")]),_._v(" "),t("td",[_._v("只接受面向个人用户的请求")])]),_._v(" "),t("tr",[t("td",[_._v("b")]),_._v(" "),t("td",[_._v("2b分组")]),_._v(" "),t("td",[_._v("只接受面向企业的请求")])]),_._v(" "),t("tr",[t("td",[_._v("t")]),_._v(" "),t("td",[_._v("面向第三方的分组")]),_._v(" "),t("td",[_._v("只接受面向第三方的请求")])])])]),_._v(" "),t("p",[_._v("下面介绍网关分组功能的操作。")]),_._v(" "),t("h2",{attrs:{id:"分组列表"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#分组列表"}},[_._v("#")]),_._v(" 分组列表")]),_._v(" "),t("p",[_._v("菜单位置:网关管理 > 网关分组。点击菜单后进入分组列表页面,如图所示。")]),_._v(" "),t("p",[t("img",{attrs:{src:"/manager_gateway_group_list_query.png",alt:"manager_gateway_group_list_query"}})]),_._v(" "),t("h2",{attrs:{id:"新增分组"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#新增分组"}},[_._v("#")]),_._v(" 新增分组")]),_._v(" "),t("p",[_._v("点击 新增 按钮弹出新增窗口,如图所示。")]),_._v(" "),t("p",[t("img",{attrs:{src:"/manager_gateway_group_add_1.png",alt:"manager_gateway_group_add_1"}})]),_._v(" "),t("p",[t("img",{attrs:{src:"/manager_gateway_group_add_2.png",alt:"manager_gateway_group_add_2"}})]),_._v(" "),t("p",[_._v("分组ID:分组的唯一标识,长度不能超过32个字符,必填;")]),_._v(" "),t("p",[_._v("分组名称:分组的名称,用于在分组选项时展示,长度不能超过32个字符,必填;")]),_._v(" "),t("p",[_._v("网关实例IP:Fizz网关集群内的机器IP地址,多个IP地址使用逗号分隔。")]),_._v(" "),t("h2",{attrs:{id:"编辑分组"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#编辑分组"}},[_._v("#")]),_._v(" 编辑分组")]),_._v(" "),t("p",[_._v("点击 编辑 按钮弹出编辑窗口,如图所示。")]),_._v(" "),t("p",[t("img",{attrs:{src:"/manager_gateway_group_edit_1.png",alt:"manager_gateway_group_edit_1"}})]),_._v(" "),t("p",[t("img",{attrs:{src:"/manager_gateway_group_edit_2.png",alt:"manager_gateway_group_edit_2"}})]),_._v(" "),t("h2",{attrs:{id:"删除分组"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#删除分组"}},[_._v("#")]),_._v(" 删除分组")]),_._v(" "),t("p",[_._v("点击 删除 按钮弹出删除确认窗口,如图所示。")]),_._v(" "),t("p",[t("img",{attrs:{src:"/manager_gateway_group_delete_1.png",alt:"manager_gateway_group_delete_1"}})]),_._v(" "),t("p",[t("img",{attrs:{src:"/manager_gateway_group_delete_2.png",alt:"manager_gateway_group_delete_2"}})]),_._v(" "),t("p",[_._v("点击 确定 按钮后删除网关分组,如果网关分组存在关联的路由配置时,需要将关联的路由配置全部删除后才能删除分组。")])])}),[],!1,null,null,null);a.default=e.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[22],{367:function(_,a,t){"use strict";t.r(a);var r=t(42),e=Object(r.a)({},(function(){var _=this,a=_.$createElement,t=_._self._c||a;return t("ContentSlotsDistributor",{attrs:{"slot-key":_.$parent.slotKey}},[t("h2",{attrs:{id:"概述"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#概述"}},[_._v("#")]),_._v(" 概述")]),_._v(" "),t("p",[_._v("网关分组功能用于维护分组元数据,将网关实例IP与分组关联,通过为不同的分组配置不同的路由策略,从而实现网关的分组管理。")]),_._v(" "),t("h2",{attrs:{id:"分组示例"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#分组示例"}},[_._v("#")]),_._v(" 分组示例")]),_._v(" "),t("p",[_._v("我们的线上业务涉及To C(个人用户)、To B(企业)、To T(第三方),对于不同业务会有对应的机器接受请求访问,不同的业务需要有各自的路由策略,因此进行了如下的分组划分。")]),_._v(" "),t("table",[t("thead",[t("tr",[t("th",[_._v("分组ID")]),_._v(" "),t("th",[_._v("分组名称")]),_._v(" "),t("th",[_._v("描述")])])]),_._v(" "),t("tbody",[t("tr",[t("td",[_._v("default")]),_._v(" "),t("td",[_._v("默认分组")]),_._v(" "),t("td",[_._v("默认分组是后台默认创建的分组,不用指定IP,不属于其它分组的机器都归到默认分组,默认分组不可修改或删除")])]),_._v(" "),t("tr",[t("td",[_._v("c")]),_._v(" "),t("td",[_._v("2c分组")]),_._v(" "),t("td",[_._v("只接受面向个人用户的请求")])]),_._v(" "),t("tr",[t("td",[_._v("b")]),_._v(" "),t("td",[_._v("2b分组")]),_._v(" "),t("td",[_._v("只接受面向企业的请求")])]),_._v(" "),t("tr",[t("td",[_._v("t")]),_._v(" "),t("td",[_._v("面向第三方的分组")]),_._v(" "),t("td",[_._v("只接受面向第三方的请求")])])])]),_._v(" "),t("p",[_._v("下面介绍网关分组功能的操作。")]),_._v(" "),t("h2",{attrs:{id:"分组列表"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#分组列表"}},[_._v("#")]),_._v(" 分组列表")]),_._v(" "),t("p",[_._v("菜单位置:网关管理 > 网关分组。点击菜单后进入分组列表页面,如图所示。")]),_._v(" "),t("p",[t("img",{attrs:{src:"/manager_gateway_group_list_query.png",alt:"manager_gateway_group_list_query"}})]),_._v(" "),t("h2",{attrs:{id:"新增分组"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#新增分组"}},[_._v("#")]),_._v(" 新增分组")]),_._v(" "),t("p",[_._v("点击 新增 按钮弹出新增窗口,如图所示。")]),_._v(" "),t("p",[t("img",{attrs:{src:"/manager_gateway_group_add_1.png",alt:"manager_gateway_group_add_1"}})]),_._v(" "),t("p",[t("img",{attrs:{src:"/manager_gateway_group_add_2.png",alt:"manager_gateway_group_add_2"}})]),_._v(" "),t("p",[_._v("分组ID:分组的唯一标识,长度不能超过32个字符,必填;")]),_._v(" "),t("p",[_._v("分组名称:分组的名称,用于在分组选项时展示,长度不能超过32个字符,必填;")]),_._v(" "),t("p",[_._v("网关实例IP:Fizz网关集群内的机器IP地址,多个IP地址使用逗号分隔。")]),_._v(" "),t("h2",{attrs:{id:"编辑分组"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#编辑分组"}},[_._v("#")]),_._v(" 编辑分组")]),_._v(" "),t("p",[_._v("点击 编辑 按钮弹出编辑窗口,如图所示。")]),_._v(" "),t("p",[t("img",{attrs:{src:"/manager_gateway_group_edit_1.png",alt:"manager_gateway_group_edit_1"}})]),_._v(" "),t("p",[t("img",{attrs:{src:"/manager_gateway_group_edit_2.png",alt:"manager_gateway_group_edit_2"}})]),_._v(" "),t("h2",{attrs:{id:"删除分组"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#删除分组"}},[_._v("#")]),_._v(" 删除分组")]),_._v(" "),t("p",[_._v("点击 删除 按钮弹出删除确认窗口,如图所示。")]),_._v(" "),t("p",[t("img",{attrs:{src:"/manager_gateway_group_delete_1.png",alt:"manager_gateway_group_delete_1"}})]),_._v(" "),t("p",[t("img",{attrs:{src:"/manager_gateway_group_delete_2.png",alt:"manager_gateway_group_delete_2"}})]),_._v(" "),t("p",[_._v("点击 确定 按钮后删除网关分组,如果网关分组存在关联的路由配置时,需要将关联的路由配置全部删除后才能删除分组。")])])}),[],!1,null,null,null);a.default=e.exports}}]); \ No newline at end of file diff --git a/docs/assets/js/23.5b796ecf.js b/docs/assets/js/23.94679012.js similarity index 98% rename from docs/assets/js/23.5b796ecf.js rename to docs/assets/js/23.94679012.js index 6e6ccac..643be96 100644 --- a/docs/assets/js/23.5b796ecf.js +++ b/docs/assets/js/23.94679012.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[23],{369:function(v,_,i){"use strict";i.r(_);var a=i(42),t=Object(a.a)({},(function(){var v=this,_=v.$createElement,i=v._self._c||_;return i("ContentSlotsDistributor",{attrs:{"slot-key":v.$parent.slotKey}},[i("h2",{attrs:{id:"概述"}},[i("a",{staticClass:"header-anchor",attrs:{href:"#概述"}},[v._v("#")]),v._v(" 概述")]),v._v(" "),i("p",[v._v("Fizz管理后台是Fizz网关的配套系统,基于Java、Vue开发,通过界面对Fizz网关集群进行各项配置。")]),v._v(" "),i("h2",{attrs:{id:"功能"}},[i("a",{staticClass:"header-anchor",attrs:{href:"#功能"}},[v._v("#")]),v._v(" 功能")]),v._v(" "),i("p",[v._v("Fizz管理后台包含如下功能:")]),v._v(" "),i("ul",[i("li",[v._v("网关管理\n"),i("ul",[i("li",[v._v("网关分组:对Fizz网关集群内的机器进行逻辑上的分组,针对不同的分组可配置不同的路由策略。")]),v._v(" "),i("li",[v._v("插件管理:维护插件元数据,定义路由级别的自定义属性、插件级别的自定义配置信息。")]),v._v(" "),i("li",[v._v("appID管理:配置应用鉴权信息,可配置是否启用签名、是否启用IP白名单,AppID级别的自定义配置供自定义插件使用。")]),v._v(" "),i("li",[v._v("路由管理:配置服务或API路由规则,支持按请求路径转发、转发到指定后端服务两种转发规则,支持插件配置。")]),v._v(" "),i("li",[v._v("接口统计:Fizz网关接口访问统计功能,以图表的形式展示指定时间段内每日的接口总数、访问次数,可查看接口的历史访问总次数以及最近请求时间。")])])]),v._v(" "),i("li",[v._v("服务编排\n"),i("ul",[i("li",[v._v("服务管理:聚合接口归属于服务,服务通过该功能维护,创建人自动获得服务权限,服务权限可分配,拥有权限的用户才能操作对应的接口列表。")]),v._v(" "),i("li",[v._v("接口列表:基于现有的业务微服务使用在线配置的方式快速的生成一个聚合接口,同时提供在线测试功能,发布历史版本查看。")]),v._v(" "),i("li",[v._v("操作日志:查看聚合接口的新增、修改、发布、下线、回滚、删除操作日志。")]),v._v(" "),i("li",[v._v("网关缓存:查看Fizz网关当前在线的实例列表以及对应实例本地缓存的已发布接口信息。")])])]),v._v(" "),i("li",[v._v("发布申请\n"),i("ul",[i("li",[v._v("我的申请:提交接口发布|下线申请,审核通过后可以对相关接口执行发布|下线操作。")]),v._v(" "),i("li",[v._v("待审核:审核发布|下线申请。")]),v._v(" "),i("li",[v._v("审核日志:查看审核发布|下线申请操作日志。")])])]),v._v(" "),i("li",[v._v("权限管理\n"),i("ul",[i("li",[v._v("角色管理:维护角色数据,为角色分配权限。")])])]),v._v(" "),i("li",[v._v("系统管理\n"),i("ul",[i("li",[v._v("用户管理:维护用户数据,为用户分配角色。")])])])]),v._v(" "),i("h2",{attrs:{id:"界面"}},[i("a",{staticClass:"header-anchor",attrs:{href:"#界面"}},[v._v("#")]),v._v(" 界面")]),v._v(" "),i("p",[i("img",{attrs:{src:"/manager_overview_1.png",alt:"manager_overview_1"}})]),v._v(" "),i("p",[i("img",{attrs:{src:"/manager_overview_2.png",alt:"manager_overview_2"}})])])}),[],!1,null,null,null);_.default=t.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[23],{370:function(v,_,i){"use strict";i.r(_);var a=i(42),t=Object(a.a)({},(function(){var v=this,_=v.$createElement,i=v._self._c||_;return i("ContentSlotsDistributor",{attrs:{"slot-key":v.$parent.slotKey}},[i("h2",{attrs:{id:"概述"}},[i("a",{staticClass:"header-anchor",attrs:{href:"#概述"}},[v._v("#")]),v._v(" 概述")]),v._v(" "),i("p",[v._v("Fizz管理后台是Fizz网关的配套系统,基于Java、Vue开发,通过界面对Fizz网关集群进行各项配置。")]),v._v(" "),i("h2",{attrs:{id:"功能"}},[i("a",{staticClass:"header-anchor",attrs:{href:"#功能"}},[v._v("#")]),v._v(" 功能")]),v._v(" "),i("p",[v._v("Fizz管理后台包含如下功能:")]),v._v(" "),i("ul",[i("li",[v._v("网关管理\n"),i("ul",[i("li",[v._v("网关分组:对Fizz网关集群内的机器进行逻辑上的分组,针对不同的分组可配置不同的路由策略。")]),v._v(" "),i("li",[v._v("插件管理:维护插件元数据,定义路由级别的自定义属性、插件级别的自定义配置信息。")]),v._v(" "),i("li",[v._v("appID管理:配置应用鉴权信息,可配置是否启用签名、是否启用IP白名单,AppID级别的自定义配置供自定义插件使用。")]),v._v(" "),i("li",[v._v("路由管理:配置服务或API路由规则,支持按请求路径转发、转发到指定后端服务两种转发规则,支持插件配置。")]),v._v(" "),i("li",[v._v("接口统计:Fizz网关接口访问统计功能,以图表的形式展示指定时间段内每日的接口总数、访问次数,可查看接口的历史访问总次数以及最近请求时间。")])])]),v._v(" "),i("li",[v._v("服务编排\n"),i("ul",[i("li",[v._v("服务管理:聚合接口归属于服务,服务通过该功能维护,创建人自动获得服务权限,服务权限可分配,拥有权限的用户才能操作对应的接口列表。")]),v._v(" "),i("li",[v._v("接口列表:基于现有的业务微服务使用在线配置的方式快速的生成一个聚合接口,同时提供在线测试功能,发布历史版本查看。")]),v._v(" "),i("li",[v._v("操作日志:查看聚合接口的新增、修改、发布、下线、回滚、删除操作日志。")]),v._v(" "),i("li",[v._v("网关缓存:查看Fizz网关当前在线的实例列表以及对应实例本地缓存的已发布接口信息。")])])]),v._v(" "),i("li",[v._v("发布申请\n"),i("ul",[i("li",[v._v("我的申请:提交接口发布|下线申请,审核通过后可以对相关接口执行发布|下线操作。")]),v._v(" "),i("li",[v._v("待审核:审核发布|下线申请。")]),v._v(" "),i("li",[v._v("审核日志:查看审核发布|下线申请操作日志。")])])]),v._v(" "),i("li",[v._v("权限管理\n"),i("ul",[i("li",[v._v("角色管理:维护角色数据,为角色分配权限。")])])]),v._v(" "),i("li",[v._v("系统管理\n"),i("ul",[i("li",[v._v("用户管理:维护用户数据,为用户分配角色。")])])])]),v._v(" "),i("h2",{attrs:{id:"界面"}},[i("a",{staticClass:"header-anchor",attrs:{href:"#界面"}},[v._v("#")]),v._v(" 界面")]),v._v(" "),i("p",[i("img",{attrs:{src:"/manager_overview_1.png",alt:"manager_overview_1"}})]),v._v(" "),i("p",[i("img",{attrs:{src:"/manager_overview_2.png",alt:"manager_overview_2"}})])])}),[],!1,null,null,null);_.default=t.exports}}]); \ No newline at end of file diff --git a/docs/assets/js/24.72fe0b8b.js b/docs/assets/js/24.9c5c2990.js similarity index 99% rename from docs/assets/js/24.72fe0b8b.js rename to docs/assets/js/24.9c5c2990.js index 2ad6773..efe1a5d 100644 --- a/docs/assets/js/24.72fe0b8b.js +++ b/docs/assets/js/24.9c5c2990.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[24],{370:function(t,s,a){"use strict";a.r(s);var n=a(42),r=Object(n.a)({},(function(){var t=this,s=t.$createElement,a=t._self._c||s;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("h2",{attrs:{id:"概述"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#概述"}},[t._v("#")]),t._v(" 概述")]),t._v(" "),a("p",[t._v("插件管理功能用于维护插件元数据,定义路由级别的自定义属性、插件级别的自定义配置信息。创建的插件用于路由管理设置时启用,当网关接受请求匹配路由规则时会触发启用的插件逻辑执行,插件逻辑中可获取到自定义的属性数据。")]),t._v(" "),a("h2",{attrs:{id:"插件列表"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#插件列表"}},[t._v("#")]),t._v(" 插件列表")]),t._v(" "),a("p",[t._v("菜单位置:网关管理 > 插件管理。点击菜单后进入插件管理列表页面,如图所示。")]),t._v(" "),a("p",[a("img",{attrs:{src:"/manager_plugin_list_query.png",alt:"manager_plugin_list_query"}})]),t._v(" "),a("h2",{attrs:{id:"新增插件"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#新增插件"}},[t._v("#")]),t._v(" 新增插件")]),t._v(" "),a("p",[t._v("点击 新增 按钮弹出新增窗口,如图所示。")]),t._v(" "),a("p",[a("img",{attrs:{src:"/manager_plugin_add_1.png",alt:"manager_plugin_add_1"}})]),t._v(" "),a("p",[a("img",{attrs:{src:"/manager_plugin_add_2.png",alt:"manager_plugin_add_2"}})]),t._v(" "),a("p",[t._v("插件名称:插件名称由英文字母、下划线或数字组成,不能以数字开头,长度不能超过50个字符,必填;")]),t._v(" "),a("p",[t._v("插件描述:插件的简要描述,长度不能超过50个字符,必填;")]),t._v(" "),a("p",[t._v("默认执行顺序:插件的默认执行顺序,按从小到大排序,值越小越先执行,取值范围0~255,必填;")]),t._v(" "),a("p",[t._v("表单定义:路由级别的自定义属性,在路由管理配置启用插件时前端会将表单定义转化为表单输入界面,更多信息请查看路由管理介绍。表单规范说明如下:")]),t._v(" "),a("div",{staticClass:"language-javascript extra-class"},[a("pre",{pre:!0,attrs:{class:"language-javascript"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/*\n* plugin_config_design\n* 动态插件参考结构\n* */")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("const")]),t._v(" pluginConfig "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/* 必有字段 */")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"field"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"inputVal"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"label"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"输入框"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"component"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"input"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// input, select, radio, checkbox,")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"dataType"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"string"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// number(long, double), string, boolean, array")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/* 可选字段 */")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"desc"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"字段的说明文字"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"placeholder"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"placeholder文字"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"default"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Aa123"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 初始默认值")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"options"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// for select, radio, checkbox")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"label"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"选项1"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"value"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// number(long, double), string, boolean,")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"label"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"选项2"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"value"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"rules"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// min|max / range / length / regex pattern")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"required"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("true")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"message"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"输入框不能为空"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"trigger"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"change"')]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// required 必填")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v('// { "min": 3, "ma x": 5, "message": "长度在 3 到 5 个字符", "trigger": "change" }, // range 长度范围(for dataType:"string")')]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v('// { "len": 8, "message": "长度需 8 个字符", "trigger": "change" }, // length 长度限制(for dataType:"string")')]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v('// { "type": "number", "message": "请输入数字类型"}, // for dataType:"number" 校验数值')]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v('// { "type": "integer", "message": "请输入整数数值", "trigger": "change" }, // for dataType:"long" 校验整数')]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v('// { "type": "float", "message": "请输入浮点数数值", "trigger": "change" }, // for dataType:"double" 校验浮点数')]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"pattern"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"^[A-Za-z\\\\d]+$"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"message"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"只能是字母或数字"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"trigger"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"change"')]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// regex pattern正则")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"field"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"selectVal"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"label"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"选择器"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"component"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"select"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"dataType"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"number"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"options"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"label"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"选项1"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"value"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"label"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"选项2"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"value"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"label"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"选项3"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"value"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("3")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"desc"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"选择器的说明文字"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"placeholder"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"请选择"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"rules"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"required"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("true")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"message"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"选择器不能为空"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"trigger"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"change"')]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"field"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"radioVal"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"label"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"单选框"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"component"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"radio"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"dataType"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"boolean"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"default"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("true")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"options"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"label"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"是"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"value"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("true")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"label"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"否"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"value"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("false")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"desc"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"单选框的说明文字"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"rules"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"required"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("true")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"message"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"请选择单选框"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"trigger"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"change"')]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"field"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"checkboxVal"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"label"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"多选框"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"component"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"checkbox"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"dataType"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"array"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"options"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"label"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"选项1"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"value"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("11")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"label"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"选项2"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"value"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("22")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"label"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"选项3"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"value"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("33")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"desc"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"多选框的说明文字"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"rules"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"required"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("true")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"message"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"请选择多选框"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"trigger"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"change"')]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// TODO 注意!!")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v('// 组件 "checkbox" 的dataType = "array"')]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v('// 组件 "radio/select" 的实际值类型等于options内的value值类型')]),t._v("\n")])])]),a("p",[t._v("自定义配置:插件级别的自定义配置信息,插件逻辑中可获取到该信息。")]),t._v(" "),a("h2",{attrs:{id:"编辑插件"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#编辑插件"}},[t._v("#")]),t._v(" 编辑插件")]),t._v(" "),a("p",[t._v("点击 编辑 按钮弹出编辑窗口,如图所示。")]),t._v(" "),a("p",[a("img",{attrs:{src:"/manager_plugin_edit_1.png",alt:"manager_plugin_edit_1"}})]),t._v(" "),a("p",[a("img",{attrs:{src:"/manager_plugin_edit_2.png",alt:"manager_plugin_edit_2"}})]),t._v(" "),a("h2",{attrs:{id:"删除插件"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#删除插件"}},[t._v("#")]),t._v(" 删除插件")]),t._v(" "),a("p",[t._v("点击 删除 按钮弹出删除确认窗口,如图所示。")]),t._v(" "),a("p",[a("img",{attrs:{src:"/manager_plugin_delete_1.png",alt:"manager_plugin_delete_1"}})]),t._v(" "),a("p",[a("img",{attrs:{src:"/manager_plugin_delete_2.png",alt:"manager_plugin_delete_2"}})]),t._v(" "),a("p",[t._v("点击 确定 按钮后删除插件,如果插件存在关联的路由配置时,需要将关联的路由配置全部删除后才能删除插件。")])])}),[],!1,null,null,null);s.default=r.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[24],{372:function(t,s,a){"use strict";a.r(s);var n=a(42),r=Object(n.a)({},(function(){var t=this,s=t.$createElement,a=t._self._c||s;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("h2",{attrs:{id:"概述"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#概述"}},[t._v("#")]),t._v(" 概述")]),t._v(" "),a("p",[t._v("插件管理功能用于维护插件元数据,定义路由级别的自定义属性、插件级别的自定义配置信息。创建的插件用于路由管理设置时启用,当网关接受请求匹配路由规则时会触发启用的插件逻辑执行,插件逻辑中可获取到自定义的属性数据。")]),t._v(" "),a("h2",{attrs:{id:"插件列表"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#插件列表"}},[t._v("#")]),t._v(" 插件列表")]),t._v(" "),a("p",[t._v("菜单位置:网关管理 > 插件管理。点击菜单后进入插件管理列表页面,如图所示。")]),t._v(" "),a("p",[a("img",{attrs:{src:"/manager_plugin_list_query.png",alt:"manager_plugin_list_query"}})]),t._v(" "),a("h2",{attrs:{id:"新增插件"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#新增插件"}},[t._v("#")]),t._v(" 新增插件")]),t._v(" "),a("p",[t._v("点击 新增 按钮弹出新增窗口,如图所示。")]),t._v(" "),a("p",[a("img",{attrs:{src:"/manager_plugin_add_1.png",alt:"manager_plugin_add_1"}})]),t._v(" "),a("p",[a("img",{attrs:{src:"/manager_plugin_add_2.png",alt:"manager_plugin_add_2"}})]),t._v(" "),a("p",[t._v("插件名称:插件名称由英文字母、下划线或数字组成,不能以数字开头,长度不能超过50个字符,必填;")]),t._v(" "),a("p",[t._v("插件描述:插件的简要描述,长度不能超过50个字符,必填;")]),t._v(" "),a("p",[t._v("默认执行顺序:插件的默认执行顺序,按从小到大排序,值越小越先执行,取值范围0~255,必填;")]),t._v(" "),a("p",[t._v("表单定义:路由级别的自定义属性,在路由管理配置启用插件时前端会将表单定义转化为表单输入界面,更多信息请查看路由管理介绍。表单规范说明如下:")]),t._v(" "),a("div",{staticClass:"language-javascript extra-class"},[a("pre",{pre:!0,attrs:{class:"language-javascript"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/*\n* plugin_config_design\n* 动态插件参考结构\n* */")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("const")]),t._v(" pluginConfig "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/* 必有字段 */")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"field"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"inputVal"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"label"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"输入框"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"component"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"input"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// input, select, radio, checkbox,")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"dataType"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"string"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// number(long, double), string, boolean, array")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/* 可选字段 */")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"desc"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"字段的说明文字"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"placeholder"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"placeholder文字"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"default"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Aa123"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 初始默认值")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"options"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// for select, radio, checkbox")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"label"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"选项1"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"value"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// number(long, double), string, boolean,")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"label"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"选项2"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"value"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"rules"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// min|max / range / length / regex pattern")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"required"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("true")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"message"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"输入框不能为空"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"trigger"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"change"')]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// required 必填")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v('// { "min": 3, "ma x": 5, "message": "长度在 3 到 5 个字符", "trigger": "change" }, // range 长度范围(for dataType:"string")')]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v('// { "len": 8, "message": "长度需 8 个字符", "trigger": "change" }, // length 长度限制(for dataType:"string")')]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v('// { "type": "number", "message": "请输入数字类型"}, // for dataType:"number" 校验数值')]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v('// { "type": "integer", "message": "请输入整数数值", "trigger": "change" }, // for dataType:"long" 校验整数')]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v('// { "type": "float", "message": "请输入浮点数数值", "trigger": "change" }, // for dataType:"double" 校验浮点数')]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"pattern"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"^[A-Za-z\\\\d]+$"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"message"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"只能是字母或数字"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"trigger"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"change"')]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// regex pattern正则")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"field"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"selectVal"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"label"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"选择器"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"component"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"select"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"dataType"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"number"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"options"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"label"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"选项1"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"value"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"label"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"选项2"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"value"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"label"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"选项3"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"value"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("3")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"desc"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"选择器的说明文字"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"placeholder"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"请选择"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"rules"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"required"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("true")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"message"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"选择器不能为空"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"trigger"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"change"')]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"field"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"radioVal"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"label"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"单选框"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"component"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"radio"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"dataType"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"boolean"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"default"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("true")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"options"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"label"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"是"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"value"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("true")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"label"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"否"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"value"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("false")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"desc"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"单选框的说明文字"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"rules"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"required"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("true")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"message"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"请选择单选框"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"trigger"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"change"')]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"field"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"checkboxVal"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"label"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"多选框"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"component"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"checkbox"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"dataType"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"array"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"options"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"label"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"选项1"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"value"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("11")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"label"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"选项2"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"value"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("22")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"label"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"选项3"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"value"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("33")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"desc"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"多选框的说明文字"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"rules"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"required"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("true")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"message"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"请选择多选框"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"trigger"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"change"')]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// TODO 注意!!")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v('// 组件 "checkbox" 的dataType = "array"')]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v('// 组件 "radio/select" 的实际值类型等于options内的value值类型')]),t._v("\n")])])]),a("p",[t._v("自定义配置:插件级别的自定义配置信息,插件逻辑中可获取到该信息。")]),t._v(" "),a("h2",{attrs:{id:"编辑插件"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#编辑插件"}},[t._v("#")]),t._v(" 编辑插件")]),t._v(" "),a("p",[t._v("点击 编辑 按钮弹出编辑窗口,如图所示。")]),t._v(" "),a("p",[a("img",{attrs:{src:"/manager_plugin_edit_1.png",alt:"manager_plugin_edit_1"}})]),t._v(" "),a("p",[a("img",{attrs:{src:"/manager_plugin_edit_2.png",alt:"manager_plugin_edit_2"}})]),t._v(" "),a("h2",{attrs:{id:"删除插件"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#删除插件"}},[t._v("#")]),t._v(" 删除插件")]),t._v(" "),a("p",[t._v("点击 删除 按钮弹出删除确认窗口,如图所示。")]),t._v(" "),a("p",[a("img",{attrs:{src:"/manager_plugin_delete_1.png",alt:"manager_plugin_delete_1"}})]),t._v(" "),a("p",[a("img",{attrs:{src:"/manager_plugin_delete_2.png",alt:"manager_plugin_delete_2"}})]),t._v(" "),a("p",[t._v("点击 确定 按钮后删除插件,如果插件存在关联的路由配置时,需要将关联的路由配置全部删除后才能删除插件。")])])}),[],!1,null,null,null);s.default=r.exports}}]); \ No newline at end of file diff --git a/docs/assets/js/25.bbf8bff1.js b/docs/assets/js/25.aead8972.js similarity index 97% rename from docs/assets/js/25.bbf8bff1.js rename to docs/assets/js/25.aead8972.js index 7f3b92c..0256952 100644 --- a/docs/assets/js/25.bbf8bff1.js +++ b/docs/assets/js/25.aead8972.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[25],{371:function(a,r,t){"use strict";t.r(r);var _=t(42),e=Object(_.a)({},(function(){var a=this,r=a.$createElement,t=a._self._c||r;return t("ContentSlotsDistributor",{attrs:{"slot-key":a.$parent.slotKey}},[t("h2",{attrs:{id:"概述"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#概述"}},[a._v("#")]),a._v(" 概述")]),a._v(" "),t("p",[a._v("角色管理功能维护角色元数据,通过配置角色拥有的菜单资源,限制用户只能操作拥有的角色对应的菜单资源,下面介绍角色管理功能的操作。")]),a._v(" "),t("h2",{attrs:{id:"角色列表"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#角色列表"}},[a._v("#")]),a._v(" 角色列表")]),a._v(" "),t("p",[a._v("菜单位置:权限管理 > 角色管理。点击菜单后进入角色列表页面,如图所示。")]),a._v(" "),t("p",[t("img",{attrs:{src:"/manager_role_list_query.png",alt:"manager_role_list_query"}})]),a._v(" "),t("h2",{attrs:{id:"添加角色"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#添加角色"}},[a._v("#")]),a._v(" 添加角色")]),a._v(" "),t("p",[a._v("点击 新增 按钮弹出新增窗口,如图所示。")]),a._v(" "),t("p",[t("img",{attrs:{src:"/manager_role_add_1.png",alt:"manager_role_add_1"}})]),a._v(" "),t("p",[t("img",{attrs:{src:"/manager_role_add_2.png",alt:"manager_role_add_2"}})]),a._v(" "),t("h2",{attrs:{id:"权限设置"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#权限设置"}},[a._v("#")]),a._v(" 权限设置")]),a._v(" "),t("p",[a._v("勾选需要分配权限的角色,点击 权限设置 按钮弹出角色权限配置窗口,如图所示。")]),a._v(" "),t("p",[t("img",{attrs:{src:"/manager_role_auth_1.png",alt:"manager_role_auth_1"}})]),a._v(" "),t("p",[t("img",{attrs:{src:"/manager_role_auth_2.png",alt:"manager_role_auth_2"}})]),a._v(" "),t("p",[a._v("勾选菜单后点击 确定 按钮确认给角色分配菜单权限。")]),a._v(" "),t("h2",{attrs:{id:"编辑角色"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#编辑角色"}},[a._v("#")]),a._v(" 编辑角色")]),a._v(" "),t("p",[a._v("点击 编辑 按钮弹出编辑窗口,如图所示。")]),a._v(" "),t("p",[t("img",{attrs:{src:"/manager_role_edit_1.png",alt:"manager_role_edit_1"}})]),a._v(" "),t("p",[t("img",{attrs:{src:"/manager_role_edit_2.png",alt:"manager_role_edit_2"}})]),a._v(" "),t("h2",{attrs:{id:"删除角色"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#删除角色"}},[a._v("#")]),a._v(" 删除角色")]),a._v(" "),t("p",[a._v("点击 删除 按钮弹出删除确认窗口,如图所示。")]),a._v(" "),t("p",[t("img",{attrs:{src:"/manager_role_delete_1.png",alt:"manager_role_delete_1"}})]),a._v(" "),t("p",[t("img",{attrs:{src:"/manager_role_delete_2.png",alt:"manager_role_delete_2"}})]),a._v(" "),t("p",[a._v("点击 确定 按钮后删除角色。")])])}),[],!1,null,null,null);r.default=e.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[25],{369:function(a,r,t){"use strict";t.r(r);var _=t(42),e=Object(_.a)({},(function(){var a=this,r=a.$createElement,t=a._self._c||r;return t("ContentSlotsDistributor",{attrs:{"slot-key":a.$parent.slotKey}},[t("h2",{attrs:{id:"概述"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#概述"}},[a._v("#")]),a._v(" 概述")]),a._v(" "),t("p",[a._v("角色管理功能维护角色元数据,通过配置角色拥有的菜单资源,限制用户只能操作拥有的角色对应的菜单资源,下面介绍角色管理功能的操作。")]),a._v(" "),t("h2",{attrs:{id:"角色列表"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#角色列表"}},[a._v("#")]),a._v(" 角色列表")]),a._v(" "),t("p",[a._v("菜单位置:权限管理 > 角色管理。点击菜单后进入角色列表页面,如图所示。")]),a._v(" "),t("p",[t("img",{attrs:{src:"/manager_role_list_query.png",alt:"manager_role_list_query"}})]),a._v(" "),t("h2",{attrs:{id:"添加角色"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#添加角色"}},[a._v("#")]),a._v(" 添加角色")]),a._v(" "),t("p",[a._v("点击 新增 按钮弹出新增窗口,如图所示。")]),a._v(" "),t("p",[t("img",{attrs:{src:"/manager_role_add_1.png",alt:"manager_role_add_1"}})]),a._v(" "),t("p",[t("img",{attrs:{src:"/manager_role_add_2.png",alt:"manager_role_add_2"}})]),a._v(" "),t("h2",{attrs:{id:"权限设置"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#权限设置"}},[a._v("#")]),a._v(" 权限设置")]),a._v(" "),t("p",[a._v("勾选需要分配权限的角色,点击 权限设置 按钮弹出角色权限配置窗口,如图所示。")]),a._v(" "),t("p",[t("img",{attrs:{src:"/manager_role_auth_1.png",alt:"manager_role_auth_1"}})]),a._v(" "),t("p",[t("img",{attrs:{src:"/manager_role_auth_2.png",alt:"manager_role_auth_2"}})]),a._v(" "),t("p",[a._v("勾选菜单后点击 确定 按钮确认给角色分配菜单权限。")]),a._v(" "),t("h2",{attrs:{id:"编辑角色"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#编辑角色"}},[a._v("#")]),a._v(" 编辑角色")]),a._v(" "),t("p",[a._v("点击 编辑 按钮弹出编辑窗口,如图所示。")]),a._v(" "),t("p",[t("img",{attrs:{src:"/manager_role_edit_1.png",alt:"manager_role_edit_1"}})]),a._v(" "),t("p",[t("img",{attrs:{src:"/manager_role_edit_2.png",alt:"manager_role_edit_2"}})]),a._v(" "),t("h2",{attrs:{id:"删除角色"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#删除角色"}},[a._v("#")]),a._v(" 删除角色")]),a._v(" "),t("p",[a._v("点击 删除 按钮弹出删除确认窗口,如图所示。")]),a._v(" "),t("p",[t("img",{attrs:{src:"/manager_role_delete_1.png",alt:"manager_role_delete_1"}})]),a._v(" "),t("p",[t("img",{attrs:{src:"/manager_role_delete_2.png",alt:"manager_role_delete_2"}})]),a._v(" "),t("p",[a._v("点击 确定 按钮后删除角色。")])])}),[],!1,null,null,null);r.default=e.exports}}]); \ No newline at end of file diff --git a/docs/assets/js/26.70321f43.js b/docs/assets/js/26.b4625fe9.js similarity index 98% rename from docs/assets/js/26.70321f43.js rename to docs/assets/js/26.b4625fe9.js index f503678..e20ad62 100644 --- a/docs/assets/js/26.70321f43.js +++ b/docs/assets/js/26.b4625fe9.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[26],{372:function(a,e,_){"use strict";_.r(e);var r=_(42),t=Object(r.a)({},(function(){var a=this,e=a.$createElement,_=a._self._c||e;return _("ContentSlotsDistributor",{attrs:{"slot-key":a.$parent.slotKey}},[_("h2",{attrs:{id:"概述"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#概述"}},[a._v("#")]),a._v(" 概述")]),a._v(" "),_("p",[a._v("服务管理功能维护服务元数据。服务编排中的服务是一个逻辑上的概念,用于对聚合接口的归类以及权限的分配。Fizz网关聚合接口的请求路径格式为 http://{ip}:{port}/proxy/{service}{apiPath},服务对应{service}段。")]),a._v(" "),_("h2",{attrs:{id:"服务列表"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#服务列表"}},[a._v("#")]),a._v(" 服务列表")]),a._v(" "),_("p",[a._v("菜单位置:服务编排 > 服务管理。点击菜单后进入服务列表页面,如图所示。")]),a._v(" "),_("p",[_("img",{attrs:{src:"/manager_service_list_query.png",alt:"manager_service_list_query"}})]),a._v(" "),_("h2",{attrs:{id:"新增服务"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#新增服务"}},[a._v("#")]),a._v(" 新增服务")]),a._v(" "),_("p",[a._v("点击 新增 按钮弹出新增窗口,如图所示。")]),a._v(" "),_("p",[_("img",{attrs:{src:"/manager_service_add_1.png",alt:"manager_service_add_1"}})]),a._v(" "),_("p",[_("img",{attrs:{src:"/manager_service_add_2.png",alt:"manager_service_add_2"}})]),a._v(" "),_("p",[a._v("服务 ID:服务唯一标识,对应Fizz网关聚合接口请求路径(格式为 http://{ip}:{port}/proxy/{service}{apiPath})的{service}段,长度不能超过200个字符,必填;")]),a._v(" "),_("p",[a._v("服务名:服务名称,用于展示或者选项使用,必填;")]),a._v(" "),_("p",[a._v("团队:团队名称,长度不能超过200个字符;")]),a._v(" "),_("p",[a._v("负责人:负责人名称,长度不能超过200个字符;")]),a._v(" "),_("p",[a._v("描述:服务描述,长度不能超过2000个字符。")]),a._v(" "),_("h2",{attrs:{id:"编辑服务"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#编辑服务"}},[a._v("#")]),a._v(" 编辑服务")]),a._v(" "),_("p",[a._v("点击 编辑 按钮弹出编辑窗口,如图所示。")]),a._v(" "),_("p",[_("img",{attrs:{src:"/manager_service_edit_1.png",alt:"manager_service_edit_1"}})]),a._v(" "),_("p",[_("img",{attrs:{src:"/manager_service_edit_2.png",alt:"manager_service_edit_2"}})]),a._v(" "),_("h2",{attrs:{id:"删除服务"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#删除服务"}},[a._v("#")]),a._v(" 删除服务")]),a._v(" "),_("p",[a._v("点击 删除 按钮弹出删除确认窗口,如图所示。")]),a._v(" "),_("p",[_("img",{attrs:{src:"/manager_service_delete_1.png",alt:"manager_service_delete_1"}})]),a._v(" "),_("p",[_("img",{attrs:{src:"/manager_service_delete_2.png",alt:"manager_service_delete_2"}})]),a._v(" "),_("p",[a._v("点击 确定 按钮后删除服务,如果服务存在关联的聚合接口时,需要将关联的聚合接口全部删除后才能删除服务。")]),a._v(" "),_("h2",{attrs:{id:"服务权限分配"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#服务权限分配"}},[a._v("#")]),a._v(" 服务权限分配")]),a._v(" "),_("p",[a._v("点击 权限 按钮弹出权限配置窗口,如图所示。")]),a._v(" "),_("p",[_("img",{attrs:{src:"/manager_service_auth_1.png",alt:"manager_service_auth_1"}})]),a._v(" "),_("p",[_("img",{attrs:{src:"/manager_service_auth_2.png",alt:"manager_service_auth_2"}})]),a._v(" "),_("p",[a._v("服务创建人自动获得服务权限,服务权限可分配,拥有权限的用户才能操作对应的接口列表。")])])}),[],!1,null,null,null);e.default=t.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[26],{375:function(a,e,_){"use strict";_.r(e);var r=_(42),t=Object(r.a)({},(function(){var a=this,e=a.$createElement,_=a._self._c||e;return _("ContentSlotsDistributor",{attrs:{"slot-key":a.$parent.slotKey}},[_("h2",{attrs:{id:"概述"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#概述"}},[a._v("#")]),a._v(" 概述")]),a._v(" "),_("p",[a._v("服务管理功能维护服务元数据。服务编排中的服务是一个逻辑上的概念,用于对聚合接口的归类以及权限的分配。Fizz网关聚合接口的请求路径格式为 http://{ip}:{port}/proxy/{service}{apiPath},服务对应{service}段。")]),a._v(" "),_("h2",{attrs:{id:"服务列表"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#服务列表"}},[a._v("#")]),a._v(" 服务列表")]),a._v(" "),_("p",[a._v("菜单位置:服务编排 > 服务管理。点击菜单后进入服务列表页面,如图所示。")]),a._v(" "),_("p",[_("img",{attrs:{src:"/manager_service_list_query.png",alt:"manager_service_list_query"}})]),a._v(" "),_("h2",{attrs:{id:"新增服务"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#新增服务"}},[a._v("#")]),a._v(" 新增服务")]),a._v(" "),_("p",[a._v("点击 新增 按钮弹出新增窗口,如图所示。")]),a._v(" "),_("p",[_("img",{attrs:{src:"/manager_service_add_1.png",alt:"manager_service_add_1"}})]),a._v(" "),_("p",[_("img",{attrs:{src:"/manager_service_add_2.png",alt:"manager_service_add_2"}})]),a._v(" "),_("p",[a._v("服务 ID:服务唯一标识,对应Fizz网关聚合接口请求路径(格式为 http://{ip}:{port}/proxy/{service}{apiPath})的{service}段,长度不能超过200个字符,必填;")]),a._v(" "),_("p",[a._v("服务名:服务名称,用于展示或者选项使用,必填;")]),a._v(" "),_("p",[a._v("团队:团队名称,长度不能超过200个字符;")]),a._v(" "),_("p",[a._v("负责人:负责人名称,长度不能超过200个字符;")]),a._v(" "),_("p",[a._v("描述:服务描述,长度不能超过2000个字符。")]),a._v(" "),_("h2",{attrs:{id:"编辑服务"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#编辑服务"}},[a._v("#")]),a._v(" 编辑服务")]),a._v(" "),_("p",[a._v("点击 编辑 按钮弹出编辑窗口,如图所示。")]),a._v(" "),_("p",[_("img",{attrs:{src:"/manager_service_edit_1.png",alt:"manager_service_edit_1"}})]),a._v(" "),_("p",[_("img",{attrs:{src:"/manager_service_edit_2.png",alt:"manager_service_edit_2"}})]),a._v(" "),_("h2",{attrs:{id:"删除服务"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#删除服务"}},[a._v("#")]),a._v(" 删除服务")]),a._v(" "),_("p",[a._v("点击 删除 按钮弹出删除确认窗口,如图所示。")]),a._v(" "),_("p",[_("img",{attrs:{src:"/manager_service_delete_1.png",alt:"manager_service_delete_1"}})]),a._v(" "),_("p",[_("img",{attrs:{src:"/manager_service_delete_2.png",alt:"manager_service_delete_2"}})]),a._v(" "),_("p",[a._v("点击 确定 按钮后删除服务,如果服务存在关联的聚合接口时,需要将关联的聚合接口全部删除后才能删除服务。")]),a._v(" "),_("h2",{attrs:{id:"服务权限分配"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#服务权限分配"}},[a._v("#")]),a._v(" 服务权限分配")]),a._v(" "),_("p",[a._v("点击 权限 按钮弹出权限配置窗口,如图所示。")]),a._v(" "),_("p",[_("img",{attrs:{src:"/manager_service_auth_1.png",alt:"manager_service_auth_1"}})]),a._v(" "),_("p",[_("img",{attrs:{src:"/manager_service_auth_2.png",alt:"manager_service_auth_2"}})]),a._v(" "),_("p",[a._v("服务创建人自动获得服务权限,服务权限可分配,拥有权限的用户才能操作对应的接口列表。")])])}),[],!1,null,null,null);e.default=t.exports}}]); \ No newline at end of file diff --git a/docs/assets/js/27.505a813e.js b/docs/assets/js/27.20a7e33d.js similarity index 97% rename from docs/assets/js/27.505a813e.js rename to docs/assets/js/27.20a7e33d.js index 2af9848..8861c16 100644 --- a/docs/assets/js/27.505a813e.js +++ b/docs/assets/js/27.20a7e33d.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[27],{373:function(t,a,s){"use strict";s.r(a);var _=s(42),r=Object(_.a)({},(function(){var t=this,a=t.$createElement,s=t._self._c||a;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("h2",{attrs:{id:"概述"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#概述"}},[t._v("#")]),t._v(" 概述")]),t._v(" "),s("p",[t._v("Fizz网关会将访问请求数据(IP地址、网关分组、服务、应用、请求方法、API Path、请求时间)推送到Kafka中,管理后台消费Kafka消息统计接口访问数据。")]),t._v(" "),s("p",[t._v("接口统计功能以图表的形式展示指定时间段内每日的接口总数、访问次数,可查看接口的历史访问总次数以及最近请求时间。")]),t._v(" "),s("h2",{attrs:{id:"接口访问统计"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#接口访问统计"}},[t._v("#")]),t._v(" 接口访问统计")]),t._v(" "),s("p",[t._v("菜单位置:网关管理 > 接口统计。点击菜单后进入接口统计页面,如图所示。")]),t._v(" "),s("p",[s("img",{attrs:{src:"/manager_source_statistics_1.png",alt:"manager_source_statistics_1.png"}})]),t._v(" "),s("p",[t._v("今天接口总数:从0时到当前时刻被调用不同接口的总数;")]),t._v(" "),s("p",[t._v("今天访问次数:从0时到当前时刻访问请求的总次数。")]),t._v(" "),s("p",[t._v("接口总数图表:显示指定时间段内每日被调用不同接口的总数曲线;")]),t._v(" "),s("p",[t._v("访问次数图表:显示指定时间段内每日访问请求的总次数曲线。")]),t._v(" "),s("h2",{attrs:{id:"请求统计"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#请求统计"}},[t._v("#")]),t._v(" 请求统计")]),t._v(" "),s("p",[t._v("接口统计界面下部为请求统计列表,如图所示。")]),t._v(" "),s("p",[s("img",{attrs:{src:"/manager_source_statistics_2.png",alt:"manager_source_statistics_2.png"}})]),t._v(" "),s("p",[t._v("来源IP:网关请求的实际入口IP地址;")]),t._v(" "),s("p",[t._v("请求次数:( 唯一[来源IP、网关分组、服务名、请求方法、appID、API Path])历史总请求次数;")]),t._v(" "),s("p",[t._v("最近请求时间:( 唯一[来源IP、网关分组、服务名、请求方法、appID、API Path])最近一次调用时间。")])])}),[],!1,null,null,null);a.default=r.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[27],{374:function(t,a,s){"use strict";s.r(a);var _=s(42),r=Object(_.a)({},(function(){var t=this,a=t.$createElement,s=t._self._c||a;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("h2",{attrs:{id:"概述"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#概述"}},[t._v("#")]),t._v(" 概述")]),t._v(" "),s("p",[t._v("Fizz网关会将访问请求数据(IP地址、网关分组、服务、应用、请求方法、API Path、请求时间)推送到Kafka中,管理后台消费Kafka消息统计接口访问数据。")]),t._v(" "),s("p",[t._v("接口统计功能以图表的形式展示指定时间段内每日的接口总数、访问次数,可查看接口的历史访问总次数以及最近请求时间。")]),t._v(" "),s("h2",{attrs:{id:"接口访问统计"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#接口访问统计"}},[t._v("#")]),t._v(" 接口访问统计")]),t._v(" "),s("p",[t._v("菜单位置:网关管理 > 接口统计。点击菜单后进入接口统计页面,如图所示。")]),t._v(" "),s("p",[s("img",{attrs:{src:"/manager_source_statistics_1.png",alt:"manager_source_statistics_1.png"}})]),t._v(" "),s("p",[t._v("今天接口总数:从0时到当前时刻被调用不同接口的总数;")]),t._v(" "),s("p",[t._v("今天访问次数:从0时到当前时刻访问请求的总次数。")]),t._v(" "),s("p",[t._v("接口总数图表:显示指定时间段内每日被调用不同接口的总数曲线;")]),t._v(" "),s("p",[t._v("访问次数图表:显示指定时间段内每日访问请求的总次数曲线。")]),t._v(" "),s("h2",{attrs:{id:"请求统计"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#请求统计"}},[t._v("#")]),t._v(" 请求统计")]),t._v(" "),s("p",[t._v("接口统计界面下部为请求统计列表,如图所示。")]),t._v(" "),s("p",[s("img",{attrs:{src:"/manager_source_statistics_2.png",alt:"manager_source_statistics_2.png"}})]),t._v(" "),s("p",[t._v("来源IP:网关请求的实际入口IP地址;")]),t._v(" "),s("p",[t._v("请求次数:( 唯一[来源IP、网关分组、服务名、请求方法、appID、API Path])历史总请求次数;")]),t._v(" "),s("p",[t._v("最近请求时间:( 唯一[来源IP、网关分组、服务名、请求方法、appID、API Path])最近一次调用时间。")])])}),[],!1,null,null,null);a.default=r.exports}}]); \ No newline at end of file diff --git a/docs/assets/js/28.cdddd7aa.js b/docs/assets/js/28.3d35b618.js similarity index 97% rename from docs/assets/js/28.cdddd7aa.js rename to docs/assets/js/28.3d35b618.js index 215e2d7..e0b5dbb 100644 --- a/docs/assets/js/28.cdddd7aa.js +++ b/docs/assets/js/28.3d35b618.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[28],{374:function(a,r,_){"use strict";_.r(r);var t=_(42),e=Object(t.a)({},(function(){var a=this,r=a.$createElement,_=a._self._c||r;return _("ContentSlotsDistributor",{attrs:{"slot-key":a.$parent.slotKey}},[_("h2",{attrs:{id:"概述"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#概述"}},[a._v("#")]),a._v(" 概述")]),a._v(" "),_("p",[a._v("用户管理功能用于维护用户元数据,包括用户信息维护、密码维护、角色配置。")]),a._v(" "),_("h2",{attrs:{id:"用户列表"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#用户列表"}},[a._v("#")]),a._v(" 用户列表")]),a._v(" "),_("p",[a._v("菜单位置:系统管理 > 用户管理。点击菜单后进入用户列表页面,如图所示。")]),a._v(" "),_("p",[_("img",{attrs:{src:"/manager_user_list_query.png",alt:"manager_user_list_query"}})]),a._v(" "),_("h2",{attrs:{id:"添加用户"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#添加用户"}},[a._v("#")]),a._v(" 添加用户")]),a._v(" "),_("p",[a._v("点击 新增 按钮弹出新增窗口,如图所示。")]),a._v(" "),_("p",[_("img",{attrs:{src:"/manager_user_add_1.png",alt:"manager_user_add_1"}})]),a._v(" "),_("p",[_("img",{attrs:{src:"/manager_user_add_2.png",alt:"manager_user_add_2"}})]),a._v(" "),_("p",[a._v("电子邮箱:用户用于接收电子邮件的邮箱地址,后台涉及邮件发送业务使用该字段设置的邮箱地址来进行邮箱发送。")]),a._v(" "),_("h2",{attrs:{id:"重置密码"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#重置密码"}},[a._v("#")]),a._v(" 重置密码")]),a._v(" "),_("p",[a._v("勾选用户后点击 密码重置 按钮可为用户重置密码。")]),a._v(" "),_("p",[_("img",{attrs:{src:"/manager_user_reset_password_1.png",alt:"manager_user_reset_password_1"}})]),a._v(" "),_("p",[_("img",{attrs:{src:"/manager_user_reset_password_2.png",alt:"manager_user_reset_password_2"}})]),a._v(" "),_("p",[a._v("重置后的默认密码为"),_("code",[a._v("AsdF1234!")]),a._v("。")]),a._v(" "),_("h2",{attrs:{id:"编辑用户"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#编辑用户"}},[a._v("#")]),a._v(" 编辑用户")]),a._v(" "),_("p",[a._v("点击 编辑 按钮弹出编辑窗口,如图所示。")]),a._v(" "),_("p",[_("img",{attrs:{src:"/manager_user_edit_1.png",alt:"manager_user_edit_1"}})]),a._v(" "),_("p",[_("img",{attrs:{src:"/manager_user_edit_2.png",alt:"manager_user_edit_2"}})]),a._v(" "),_("h2",{attrs:{id:"删除用户"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#删除用户"}},[a._v("#")]),a._v(" 删除用户")]),a._v(" "),_("p",[a._v("点击 删除 按钮弹出删除确认窗口,如图所示。")]),a._v(" "),_("p",[_("img",{attrs:{src:"/manager_user_delete_1.png",alt:"manager_user_delete_1"}})]),a._v(" "),_("p",[_("img",{attrs:{src:"/manager_user_delete_2.png",alt:"manager_user_delete_2"}})])])}),[],!1,null,null,null);r.default=e.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[28],{371:function(a,r,_){"use strict";_.r(r);var t=_(42),e=Object(t.a)({},(function(){var a=this,r=a.$createElement,_=a._self._c||r;return _("ContentSlotsDistributor",{attrs:{"slot-key":a.$parent.slotKey}},[_("h2",{attrs:{id:"概述"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#概述"}},[a._v("#")]),a._v(" 概述")]),a._v(" "),_("p",[a._v("用户管理功能用于维护用户元数据,包括用户信息维护、密码维护、角色配置。")]),a._v(" "),_("h2",{attrs:{id:"用户列表"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#用户列表"}},[a._v("#")]),a._v(" 用户列表")]),a._v(" "),_("p",[a._v("菜单位置:系统管理 > 用户管理。点击菜单后进入用户列表页面,如图所示。")]),a._v(" "),_("p",[_("img",{attrs:{src:"/manager_user_list_query.png",alt:"manager_user_list_query"}})]),a._v(" "),_("h2",{attrs:{id:"添加用户"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#添加用户"}},[a._v("#")]),a._v(" 添加用户")]),a._v(" "),_("p",[a._v("点击 新增 按钮弹出新增窗口,如图所示。")]),a._v(" "),_("p",[_("img",{attrs:{src:"/manager_user_add_1.png",alt:"manager_user_add_1"}})]),a._v(" "),_("p",[_("img",{attrs:{src:"/manager_user_add_2.png",alt:"manager_user_add_2"}})]),a._v(" "),_("p",[a._v("电子邮箱:用户用于接收电子邮件的邮箱地址,后台涉及邮件发送业务使用该字段设置的邮箱地址来进行邮箱发送。")]),a._v(" "),_("h2",{attrs:{id:"重置密码"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#重置密码"}},[a._v("#")]),a._v(" 重置密码")]),a._v(" "),_("p",[a._v("勾选用户后点击 密码重置 按钮可为用户重置密码。")]),a._v(" "),_("p",[_("img",{attrs:{src:"/manager_user_reset_password_1.png",alt:"manager_user_reset_password_1"}})]),a._v(" "),_("p",[_("img",{attrs:{src:"/manager_user_reset_password_2.png",alt:"manager_user_reset_password_2"}})]),a._v(" "),_("p",[a._v("重置后的默认密码为"),_("code",[a._v("AsdF1234!")]),a._v("。")]),a._v(" "),_("h2",{attrs:{id:"编辑用户"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#编辑用户"}},[a._v("#")]),a._v(" 编辑用户")]),a._v(" "),_("p",[a._v("点击 编辑 按钮弹出编辑窗口,如图所示。")]),a._v(" "),_("p",[_("img",{attrs:{src:"/manager_user_edit_1.png",alt:"manager_user_edit_1"}})]),a._v(" "),_("p",[_("img",{attrs:{src:"/manager_user_edit_2.png",alt:"manager_user_edit_2"}})]),a._v(" "),_("h2",{attrs:{id:"删除用户"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#删除用户"}},[a._v("#")]),a._v(" 删除用户")]),a._v(" "),_("p",[a._v("点击 删除 按钮弹出删除确认窗口,如图所示。")]),a._v(" "),_("p",[_("img",{attrs:{src:"/manager_user_delete_1.png",alt:"manager_user_delete_1"}})]),a._v(" "),_("p",[_("img",{attrs:{src:"/manager_user_delete_2.png",alt:"manager_user_delete_2"}})])])}),[],!1,null,null,null);r.default=e.exports}}]); \ No newline at end of file diff --git a/docs/assets/js/30.0222f21c.js b/docs/assets/js/30.7591e88a.js similarity index 95% rename from docs/assets/js/30.0222f21c.js rename to docs/assets/js/30.7591e88a.js index ab69ee4..98c7472 100644 --- a/docs/assets/js/30.0222f21c.js +++ b/docs/assets/js/30.7591e88a.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[30],{375:function(t,e,s){"use strict";s.r(e);var a=s(42),r=Object(a.a)({},(function(){var t=this,e=t.$createElement,s=t._self._c||e;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("h2",{attrs:{id:"路由转发介绍"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#路由转发介绍"}},[t._v("#")]),t._v(" 路由转发介绍")]),t._v(" "),s("p",[t._v("路由转发也叫反向代理,为内部微服务提供统一的对外入口。支持以下功能:")]),t._v(" "),s("ul",[s("li",[t._v("支持服务注册与发现")]),t._v(" "),s("li",[t._v("支持负载均衡")]),t._v(" "),s("li",[t._v("支持黑白名单机制")]),t._v(" "),s("li",[t._v("支持配置插件")])]),t._v(" "),s("h2",{attrs:{id:"接入路由转发"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#接入路由转发"}},[t._v("#")]),t._v(" 接入路由转发")]),t._v(" "),s("ul",[s("li",[t._v("前提条件:接入Eureka注册中心")]),t._v(" "),s("li",[t._v("开通白名单,接入注册中心的服务默认不对公网开放 (白名单在配置文件里配置serviceWhiteList)")]),t._v(" "),s("li",[t._v("配置访问权限 (管理后台-接口代理-API查询)")])])])}),[],!1,null,null,null);e.default=r.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[30],{373:function(t,e,s){"use strict";s.r(e);var a=s(42),r=Object(a.a)({},(function(){var t=this,e=t.$createElement,s=t._self._c||e;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("h2",{attrs:{id:"路由转发介绍"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#路由转发介绍"}},[t._v("#")]),t._v(" 路由转发介绍")]),t._v(" "),s("p",[t._v("路由转发也叫反向代理,为内部微服务提供统一的对外入口。支持以下功能:")]),t._v(" "),s("ul",[s("li",[t._v("支持服务注册与发现")]),t._v(" "),s("li",[t._v("支持负载均衡")]),t._v(" "),s("li",[t._v("支持黑白名单机制")]),t._v(" "),s("li",[t._v("支持配置插件")])]),t._v(" "),s("h2",{attrs:{id:"接入路由转发"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#接入路由转发"}},[t._v("#")]),t._v(" 接入路由转发")]),t._v(" "),s("ul",[s("li",[t._v("前提条件:接入Eureka注册中心")]),t._v(" "),s("li",[t._v("开通白名单,接入注册中心的服务默认不对公网开放 (白名单在配置文件里配置serviceWhiteList)")]),t._v(" "),s("li",[t._v("配置访问权限 (管理后台-接口代理-API查询)")])])])}),[],!1,null,null,null);e.default=r.exports}}]); \ No newline at end of file diff --git a/docs/assets/js/5.a59b20e1.js b/docs/assets/js/5.abc10683.js similarity index 79% rename from docs/assets/js/5.a59b20e1.js rename to docs/assets/js/5.abc10683.js index 010a729..71e393b 100644 --- a/docs/assets/js/5.a59b20e1.js +++ b/docs/assets/js/5.abc10683.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[5],{352:function(t,e,n){"use strict";n.r(e);var s=n(42),l=Object(s.a)({},(function(){var t=this.$createElement;return(this._self._c||t)("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}})}),[],!1,null,null,null);e.default=l.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[5],{351:function(t,e,n){"use strict";n.r(e);var s=n(42),l=Object(s.a)({},(function(){var t=this.$createElement;return(this._self._c||t)("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}})}),[],!1,null,null,null);e.default=l.exports}}]); \ No newline at end of file diff --git a/docs/assets/js/7.00dd2642.js b/docs/assets/js/7.e3b70354.js similarity index 81% rename from docs/assets/js/7.00dd2642.js rename to docs/assets/js/7.e3b70354.js index 04bd9a0..02f8ee4 100644 --- a/docs/assets/js/7.00dd2642.js +++ b/docs/assets/js/7.e3b70354.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[7],{353:function(t,n,s){"use strict";s.r(n);var e=s(42),o=Object(e.a)({},(function(){var t=this.$createElement,n=this._self._c||t;return n("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}},[n("p",[this._v("coming soon")])])}),[],!1,null,null,null);n.default=o.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[7],{352:function(t,n,s){"use strict";s.r(n);var e=s(42),o=Object(e.a)({},(function(){var t=this.$createElement,n=this._self._c||t;return n("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}},[n("p",[this._v("coming soon")])])}),[],!1,null,null,null);n.default=o.exports}}]); \ No newline at end of file diff --git a/docs/assets/js/8.645ad4e8.js b/docs/assets/js/8.a4432ff1.js similarity index 97% rename from docs/assets/js/8.645ad4e8.js rename to docs/assets/js/8.a4432ff1.js index 2b64b46..85a1c67 100644 --- a/docs/assets/js/8.645ad4e8.js +++ b/docs/assets/js/8.a4432ff1.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[8],{351:function(t,a,r){"use strict";r.r(a);var s=r(42),_=Object(s.a)({},(function(){var t=this,a=t.$createElement,r=t._self._c||a;return r("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[r("h2",{attrs:{id:"什么是服务编排"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#什么是服务编排"}},[t._v("#")]),t._v(" 什么是服务编排")]),t._v(" "),r("p",[t._v("服务编排主要基于现有的业务微服务使用在线配置的方式快速的生成一个聚合接口。")]),t._v(" "),r("p",[t._v("特点: 在线API设计、在线测试、快速开发")]),t._v(" "),r("h2",{attrs:{id:"举例说明"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#举例说明"}},[t._v("#")]),t._v(" 举例说明")]),t._v(" "),r("p",[t._v("订单详情页面需要展示订单信息、商品信息和用户信息。可通过配置的方式生成一个接口先后调用底层微服务的订单详情接口、商品信息接口和用户信息接口,再从这3个接口的返回结果里提取需要的字段返回给前端页面。")]),t._v(" "),r("h2",{attrs:{id:"服务编排架构"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#服务编排架构"}},[t._v("#")]),t._v(" 服务编排架构")]),t._v(" "),r("p",[r("img",{attrs:{src:"/fizz_aggregate.jpg",alt:""}})]),t._v(" "),r("h2",{attrs:{id:"适用场景"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#适用场景"}},[t._v("#")]),t._v(" 适用场景")]),t._v(" "),r("h3",{attrs:{id:"前端"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#前端"}},[t._v("#")]),t._v(" 前端")]),t._v(" "),r("p",[t._v("1、一个页面调用多个接口时,可以编排好返回聚合结果,提高页面数据的加载速度")]),t._v(" "),r("p",[t._v("2、移动设备计算能力有限,可以把数据计算或业务处理逻辑放到服务端完成,加快页面响应")]),t._v(" "),r("h3",{attrs:{id:"后端"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#后端"}},[t._v("#")]),t._v(" 后端")]),t._v(" "),r("p",[t._v("1、替换应用层的聚合接口,减少应用层的胶水代码")]),t._v(" "),r("p",[t._v("2、快速生成透传数据类型的接口")]),t._v(" "),r("p",[t._v("3、数据转换和映射")])])}),[],!1,null,null,null);a.default=_.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[8],{353:function(t,a,r){"use strict";r.r(a);var s=r(42),_=Object(s.a)({},(function(){var t=this,a=t.$createElement,r=t._self._c||a;return r("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[r("h2",{attrs:{id:"什么是服务编排"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#什么是服务编排"}},[t._v("#")]),t._v(" 什么是服务编排")]),t._v(" "),r("p",[t._v("服务编排主要基于现有的业务微服务使用在线配置的方式快速的生成一个聚合接口。")]),t._v(" "),r("p",[t._v("特点: 在线API设计、在线测试、快速开发")]),t._v(" "),r("h2",{attrs:{id:"举例说明"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#举例说明"}},[t._v("#")]),t._v(" 举例说明")]),t._v(" "),r("p",[t._v("订单详情页面需要展示订单信息、商品信息和用户信息。可通过配置的方式生成一个接口先后调用底层微服务的订单详情接口、商品信息接口和用户信息接口,再从这3个接口的返回结果里提取需要的字段返回给前端页面。")]),t._v(" "),r("h2",{attrs:{id:"服务编排架构"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#服务编排架构"}},[t._v("#")]),t._v(" 服务编排架构")]),t._v(" "),r("p",[r("img",{attrs:{src:"/fizz_aggregate.jpg",alt:""}})]),t._v(" "),r("h2",{attrs:{id:"适用场景"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#适用场景"}},[t._v("#")]),t._v(" 适用场景")]),t._v(" "),r("h3",{attrs:{id:"前端"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#前端"}},[t._v("#")]),t._v(" 前端")]),t._v(" "),r("p",[t._v("1、一个页面调用多个接口时,可以编排好返回聚合结果,提高页面数据的加载速度")]),t._v(" "),r("p",[t._v("2、移动设备计算能力有限,可以把数据计算或业务处理逻辑放到服务端完成,加快页面响应")]),t._v(" "),r("h3",{attrs:{id:"后端"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#后端"}},[t._v("#")]),t._v(" 后端")]),t._v(" "),r("p",[t._v("1、替换应用层的聚合接口,减少应用层的胶水代码")]),t._v(" "),r("p",[t._v("2、快速生成透传数据类型的接口")]),t._v(" "),r("p",[t._v("3、数据转换和映射")])])}),[],!1,null,null,null);a.default=_.exports}}]); \ No newline at end of file diff --git a/docs/assets/js/9.9eb9244c.js b/docs/assets/js/9.b1740bdf.js similarity index 94% rename from docs/assets/js/9.9eb9244c.js rename to docs/assets/js/9.b1740bdf.js index bd848ab..296f3f9 100644 --- a/docs/assets/js/9.9eb9244c.js +++ b/docs/assets/js/9.b1740bdf.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[9],{357:function(t,a,s){"use strict";s.r(a);var n=s(42),e=Object(n.a)({},(function(){var t=this,a=t.$createElement,s=t._self._c||a;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("h2",{attrs:{id:"创建服务"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#创建服务"}},[t._v("#")]),t._v(" 创建服务")]),t._v(" "),s("p",[s("img",{attrs:{src:"/aggr_newservice.png",alt:""}})]),t._v(" "),s("h2",{attrs:{id:"创建聚合接口"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#创建聚合接口"}},[t._v("#")]),t._v(" 创建聚合接口")]),t._v(" "),s("p",[s("img",{attrs:{src:"/aggr_newapi0.png",alt:""}}),t._v(" "),s("img",{attrs:{src:"/aggr_newapi.png",alt:""}})]),t._v(" "),s("h2",{attrs:{id:"配置输入"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#配置输入"}},[t._v("#")]),t._v(" 配置输入")]),t._v(" "),s("p",[s("img",{attrs:{src:"/aggr_config_input.png",alt:""}})]),t._v(" "),s("ul",[s("li",[t._v("配置输入的定义包括3部分:请求头、请求体和Query参数")]),t._v(" "),s("li",[t._v("基于JSON Schema规范")]),t._v(" "),s("li",[t._v("自带校验规则")]),t._v(" "),s("li",[t._v("支持自定义脚本实现复杂的逻辑校验")])]),t._v(" "),s("p",[t._v("JSON Schema规范,详见:")]),t._v(" "),s("p",[s("a",{attrs:{href:"http://json-schema.org/specification.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("http://json-schema.org/specification.html"),s("OutboundLink")],1)]),t._v(" "),s("p",[s("a",{attrs:{href:"http://json-schema.org/understanding-json-schema/",target:"_blank",rel:"noopener noreferrer"}},[t._v("http://json-schema.org/understanding-json-schema/"),s("OutboundLink")],1)]),t._v(" "),s("h2",{attrs:{id:"配置校验结果"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#配置校验结果"}},[t._v("#")]),t._v(" 配置校验结果")]),t._v(" "),s("p",[s("img",{attrs:{src:"/aggr_config_input_validate_result.png",alt:""}})]),t._v(" "),s("ul",[s("li",[t._v("校验不通过时,Fizz会把校验失败的原因(如:订单ID不能为空)放到上下文的validateMsg字段里")]),t._v(" "),s("li",[t._v("可以自定义返回给调用方的报文格式,如 msgCode, message")]),t._v(" "),s("li",[t._v("支持自定义响应头")]),t._v(" "),s("li",[t._v("支持自定义脚本处理校验结果")])]),t._v(" "),s("h2",{attrs:{id:"配置步骤"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#配置步骤"}},[t._v("#")]),t._v(" 配置步骤")]),t._v(" "),s("h3",{attrs:{id:"配置步骤的基础信息"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#配置步骤的基础信息"}},[t._v("#")]),t._v(" 配置步骤的基础信息")]),t._v(" "),s("p",[s("img",{attrs:{src:"/aggr_config_step1.png",alt:""}})]),t._v(" "),s("h3",{attrs:{id:"配置步骤的接口入出参"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#配置步骤的接口入出参"}},[t._v("#")]),t._v(" 配置步骤的接口入出参")]),t._v(" "),s("p",[s("img",{attrs:{src:"/aggr_config_step2.png",alt:""}})]),t._v(" "),s("h3",{attrs:{id:"步骤说明"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#步骤说明"}},[t._v("#")]),t._v(" 步骤说明")]),t._v(" "),s("ul",[s("li",[t._v("一个聚合接口可包含多个步骤")]),t._v(" "),s("li",[t._v("一个步骤可包含多个请求(即调用多个接口)")]),t._v(" "),s("li",[t._v("步骤间是串联顺序执行")]),t._v(" "),s("li",[t._v("一个步骤内的多个请求并行执行")])]),t._v(" "),s("h3",{attrs:{id:"数据转换"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#数据转换"}},[t._v("#")]),t._v(" 数据转换")]),t._v(" "),s("p",[t._v("支持配置固定值,引用值和脚本")]),t._v(" "),s("h4",{attrs:{id:"固定值"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#固定值"}},[t._v("#")]),t._v(" 固定值")]),t._v(" "),s("p",[s("img",{attrs:{src:"/aggr_config_step_mapping_1.png",alt:""}})]),t._v(" "),s("h4",{attrs:{id:"引用值"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#引用值"}},[t._v("#")]),t._v(" 引用值")]),t._v(" "),s("p",[s("img",{attrs:{src:"/aggr_config_step_mapping_2.png",alt:""}})]),t._v(" "),s("h4",{attrs:{id:"脚本"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#脚本"}},[t._v("#")]),t._v(" 脚本")]),t._v(" "),s("p",[s("img",{attrs:{src:"/aggr_config_step_mapping_3.png",alt:""}})]),t._v(" "),s("p",[s("img",{attrs:{src:"/aggr_config_step_mapping_4.png",alt:""}})]),t._v(" "),s("h4",{attrs:{id:"星号"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#星号"}},[t._v("#")]),t._v(" 星号 *")]),t._v(" "),s("p",[t._v("星号通配符可以接收一个返回对象类型的引用值,返回对象里的字段会合并到目标对象里")]),t._v(" "),s("p",[s("img",{attrs:{src:"/aggr_config_step_mapping_5.png",alt:""}})]),t._v(" "),s("p",[t._v('样例:userInfo = {"userName": "Fizz", "userID": 1234}')]),t._v(" "),s("h4",{attrs:{id:"优先级与覆盖顺序"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#优先级与覆盖顺序"}},[t._v("#")]),t._v(" 优先级与覆盖顺序")]),t._v(" "),s("p",[t._v("固定值 < 引用值 < 脚本 < 星号*")]),t._v(" "),s("p",[t._v("当一个字段配置了多种类型的值时按以上顺序覆盖,星号优先级最高")]),t._v(" "),s("h4",{attrs:{id:"引用值规范"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#引用值规范"}},[t._v("#")]),t._v(" 引用值规范")]),t._v(" "),s("div",{staticClass:"language-properties extra-class"},[s("pre",{pre:!0,attrs:{class:"language-properties"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 获取入参请求头aaa的值")]),t._v("\ninput.request.headers.aaa\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 获取入参请求体bbb字段的值")]),t._v("\ninput.request.body.bbb\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 获取入参URL Query参数fff字段的值")]),t._v("\ninput.request.params.fff\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 获取步骤1里request1的请求头ccc的值")]),t._v("\nstep1.request1.request.headers.ccc\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 获取步骤1里request1的响应体ddd的值")]),t._v("\nstep1.request1.response.body.ddd\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 获取步骤1结果里eee的值")]),t._v("\nstep1.result.eee\n\n")])])]),s("ul",[s("li",[t._v("支持单值引用,如:string,int等")]),t._v(" "),s("li",[t._v("支持对象类型的引用")])]),t._v(" "),s("p",[t._v("input: 表示调用方的输入数据,如H5页面提交上来的参数")]),t._v(" "),s("p",[t._v("stepN.requestN: 表示步骤N里调用接口N的相关参数")]),t._v(" "),s("p",[t._v("stepN.result: 表示步骤N的转换结果")]),t._v(" "),s("h4",{attrs:{id:"fallback与预处理条件"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#fallback与预处理条件"}},[t._v("#")]),t._v(" Fallback与预处理条件")]),t._v(" "),s("p",[s("img",{attrs:{src:"/aggr_config_step_fallback.png",alt:""}})]),t._v(" "),s("p",[t._v("Fallback:")]),t._v(" "),s("p",[t._v("当调用接口发生异常(如超时、网络或系统异常)可配置fallback方案:")]),t._v(" "),s("ul",[s("li",[t._v("Stop: 终止请求并立即返回")]),t._v(" "),s("li",[t._v("Continue: 继续后续的操作,且要设置默认的fallback json")])]),t._v(" "),s("p",[t._v("预处理: 根据条件判断是否要调用接口,脚本返回true时才调用接口")]),t._v(" "),s("h4",{attrs:{id:"配置步骤结果处理"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#配置步骤结果处理"}},[t._v("#")]),t._v(" 配置步骤结果处理")]),t._v(" "),s("p",[s("img",{attrs:{src:"/aggr_config_step_result.png",alt:""}})]),t._v(" "),s("ul",[s("li",[s("p",[t._v("支持对步骤里调用的每一个接口的返回结果做数据转换,如果配置数据转换规则原样返回并存储到上下文里供后续使用")])]),t._v(" "),s("li",[s("p",[t._v("支持对步骤里调用的一个或多个接口的返回结果做处理,并把处理完的结果存储到上下文里供后续使用,不配置则不处理")])])]),t._v(" "),s("h2",{attrs:{id:"配置输出"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#配置输出"}},[t._v("#")]),t._v(" 配置输出")]),t._v(" "),s("p",[s("img",{attrs:{src:"/aggr_config_output.png",alt:""}})]),t._v(" "),s("p",[t._v("配置返回给调用方的结果")]),t._v(" "),s("ul",[s("li",[t._v("支持配置响应头")]),t._v(" "),s("li",[t._v("支持配置响应体")]),t._v(" "),s("li",[t._v("支持自定脚本处理复杂的业务逻辑")])]),t._v(" "),s("h2",{attrs:{id:"脚本-2"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#脚本-2"}},[t._v("#")]),t._v(" 脚本")]),t._v(" "),s("p",[t._v("目前支持以下脚本语言:")]),t._v(" "),s("p",[t._v("Javascript (推荐) - ECMAScript 5标准")]),t._v(" "),s("p",[t._v("JS脚本只支持单函数,且函数名不可变,在创建脚本时系统会自动生成初始模板,模板里包含相关使用说明")]),t._v(" "),s("p",[s("img",{attrs:{src:"/aggr_config_script_1.png",alt:""}})]),t._v(" "),s("p",[t._v("Groovy")]),t._v(" "),s("p",[s("img",{attrs:{src:"/aggr_config_script_2.png",alt:""}})]),t._v(" "),s("h3",{attrs:{id:"common-js-提供了操作context上下文的便捷操作函数"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#common-js-提供了操作context上下文的便捷操作函数"}},[t._v("#")]),t._v(" common.js 提供了操作context上下文的便捷操作函数")]),t._v(" "),s("div",{staticClass:"language-javascript extra-class"},[s("pre",{pre:!0,attrs:{class:"language-javascript"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/**\n * context 上下文便捷操作函数\n *\n */")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" common "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/* *********** private function begin *********** */")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 获取上下文中客户端请求对象")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token function-variable function"}},[t._v("getInputReq")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token parameter"}},[t._v("ctx")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("ctx "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'input'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'input'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'request'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'input'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'request'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 获取上下文步骤中请求接口的请求对象")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token function-variable function"}},[t._v("getStepReq")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token parameter"}},[t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" stepName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" requestName")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("ctx "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("stepName "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("requestName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("stepName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("stepName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'requests'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("stepName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'requests'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("requestName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("stepName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'requests'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("requestName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'request'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("stepName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'requests'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("requestName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'request'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 获取上下文步骤中请求接口的响应对象")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token function-variable function"}},[t._v("getStepResp")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token parameter"}},[t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" stepName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" requestName")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("ctx "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("stepName "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("requestName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("stepName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("stepName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'requests'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("stepName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'requests'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("requestName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("stepName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'requests'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("requestName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'response'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("stepName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'requests'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("requestName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'response'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/* *********** private function end *********** */")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/* *********** input begin ************ */")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/**\n * 获取客户端请求头\n * @param {*} ctx 上下文 【必填】\n * @param {*} headerName 请求头字段名 【选填】,不传时返回所有请求头\n */")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token function-variable function"}},[t._v("getInputReqHeader")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token parameter"}},[t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" headerName")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" req "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("this")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getInputReq")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" headers "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" req"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'headers'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" headerName "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),t._v(" headers"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("headerName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" headers"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/**\n * 获取客户端URL请求参数(query string)\n * @param {*} ctx 上下文 【必填】\n * @param {*} paramName URL参数名 【选填】,不传时返回所有请求参数\n */")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token function-variable function"}},[t._v("getInputReqParam")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token parameter"}},[t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" paramName")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" req "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("this")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getInputReq")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" params "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" req"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'params'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" paramName "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),t._v(" params"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("paramName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" params"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/**\n * 获取客户端请求体\n * @param {*} ctx 上下文 【必填】\n * @param {*} field 字段名 【选填】,不传时返回整个请求体\n */")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token function-variable function"}},[t._v("getInputReqBody")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token parameter"}},[t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" field")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" req "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("this")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getInputReq")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" body "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" req"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'body'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" field "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),t._v(" body"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("field"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" body"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/**\n * 获取返回给客户端的响应头\n * @param {*} ctx 上下文 【必填】\n * @param {*} headerName 响应头字段名 【选填】,不传时返回所有响应头\n */")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token function-variable function"}},[t._v("getInputRespHeader")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token parameter"}},[t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" headerName")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" req "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("this")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getInputReq")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" headers "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" req"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'headers'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" headerName "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),t._v(" headers"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("headerName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" headers"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/**\n * 获取返回给客户端的响应体\n * @param {*} ctx 上下文 【必填】\n * @param {*} field 字段名 【选填】,不传时返回整个响应体\n */")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token function-variable function"}},[t._v("getInputRespBody")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token parameter"}},[t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" field")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" req "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("this")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getInputReq")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" body "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" req"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'body'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" field "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),t._v(" body"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("field"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" body"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/* *********** input begin ************ */")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/* *********** step request begin ************ */")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/**\n * 获取步骤中调用的接口的请求头\n * @param {*} ctx 上下文 【必填】\n * @param {*} stepName 步骤名【必填】\n * @param {*} requestName 请求的接口名 【必填】\n * @param {*} headerName 请求头字段名 【选填】,不传时返回所有请求头\n */")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token function-variable function"}},[t._v("getStepReqHeader")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token parameter"}},[t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" stepName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" requestName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" headerName")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" req "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("this")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getStepReq")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" stepName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" requestName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" headers "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" req"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'headers'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" headerName "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),t._v(" headers"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("headerName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" headers"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/**\n * 获取步骤中调用的接口的URL参数\n * @param {*} ctx 上下文 【必填】\n * @param {*} stepName 步骤名【必填】\n * @param {*} requestName 请求的接口名 【必填】\n * @param {*} paramName URL参数名 【选填】,不传时返回所有URL参数\n */")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token function-variable function"}},[t._v("getStepReqParam")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token parameter"}},[t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" stepName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" requestName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" paramName")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" req "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("this")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getStepReq")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" stepName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" requestName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" params "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" req"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'params'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" paramName "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),t._v(" params"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("paramName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" params"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/**\n * 获取步骤中调用的接口的请求体\n * @param {*} ctx 上下文 【必填】\n * @param {*} stepName 步骤名【必填】\n * @param {*} requestName 请求的接口名 【必填】\n * @param {*} field 字段名 【选填】,不传时返回整个请求体\n */")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token function-variable function"}},[t._v("getStepReqBody")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token parameter"}},[t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" stepName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" requestName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" field")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" req "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("this")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getStepReq")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" stepName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" requestName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" body "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" req"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'body'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" field "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),t._v(" body"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("field"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" body"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/**\n * 获取步骤中调用的接口的响应头\n * @param {*} ctx 上下文 【必填】\n * @param {*} stepName 步骤名【必填】\n * @param {*} requestName 请求的接口名 【必填】\n * @param {*} headerName 响应头字段名 【选填】,不传时返回所有响应头\n */")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token function-variable function"}},[t._v("getStepRespHeader")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token parameter"}},[t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" stepName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" requestName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" headerName")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" resp "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("this")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getStepResp")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" stepName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" requestName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" headers "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" resp"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'headers'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" headerName "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),t._v(" headers"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("headerName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" headers"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/**\n * 获取步骤中调用的接口的响应头\n * @param {*} ctx 上下文 【必填】\n * @param {*} stepName 步骤名【必填】\n * @param {*} requestName 请求的接口名 【必填】\n * @param {*} field 字段名 【选填】,不传时返回整个响应头\n */")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token function-variable function"}},[t._v("getStepRespBody")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token parameter"}},[t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" stepName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" requestName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" field")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" resp "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("this")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getStepResp")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" stepName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" requestName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" body "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" resp"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'body'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" field "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),t._v(" body"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("field"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" body"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/**\n * 获取步骤结果\n * @param {*} ctx 上下文 【必填】\n * @param {*} stepName 步骤名【必填】\n * @param {*} field 字段名 【选填】,不传时返回整个步骤结果对象\n */")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token function-variable function"}},[t._v("getStepResult")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token parameter"}},[t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" stepName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" field")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("ctx "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("stepName "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("stepName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" result "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("stepName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'result'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" field "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),t._v(" result"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("field"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" result"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/* *********** step request end ************ */")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n")])])]),s("h3",{attrs:{id:"context-js-数据结构"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#context-js-数据结构"}},[t._v("#")]),t._v(" context.js 数据结构")]),t._v(" "),s("div",{staticClass:"language-javascript extra-class"},[s("pre",{pre:!0,attrs:{class:"language-javascript"}},[s("code",[t._v("\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 上下文,用于保存客户输入输出和每个步骤的输入与输出结果")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" context "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 是否DEBUG模式")]),t._v("\n\tdebug"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),s("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("false")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n\t"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 各个操作的耗时")]),t._v("\n\telapsedTimes"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("actionName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("123")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 操作名称:耗时")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 客户输入和接口的返回结果")]),t._v("\n input"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n request"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n path"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('""')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n method"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"GET/POST"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n headers"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n body"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n params"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n response"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 聚合接口的响应")]),t._v("\n headers"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n body"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 步骤")]),t._v("\n step1"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n requests"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 接口1")]),t._v("\n request1"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 请求相关参数")]),t._v("\n request"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n url"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('""')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n method"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"GET/POST"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n headers"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n body"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 根据转换规则转换后的接口响应")]),t._v("\n response"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n headers"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n body"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 接口2")]),t._v("\n request2"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n request"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n url"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('""')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n method"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"GET/POST"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n headers"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n body"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n response"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n headers"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n body"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("//...")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 步骤结果")]),t._v("\n result"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n")])])]),s("h2",{attrs:{id:"异常处理"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#异常处理"}},[t._v("#")]),t._v(" 异常处理")]),t._v(" "),s("p",[t._v("当要在脚本里中止请求时可以通过以下方式来实现")]),t._v(" "),s("p",[s("img",{attrs:{src:"/aggr_config_exception.png",alt:""}})]),t._v(" "),s("p",[t._v("返回一个对象且这个对象包含一个_stopAndResponse等于true的属性,Fizz会终止后续的操作并把这个对象返回给调用方。")]),t._v(" "),s("h2",{attrs:{id:"配置路由"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#配置路由"}},[t._v("#")]),t._v(" 配置路由")]),t._v(" "),s("p",[t._v("至此服务编排的接口配置完成,但此时还不能通过网关访问接口,需要到网关管理-路由管理里配置路由")]),t._v(" "),s("p",[s("img",{attrs:{src:"/aggr_config_route.png",alt:""}})]),t._v(" "),s("h2",{attrs:{id:"在线测试"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#在线测试"}},[t._v("#")]),t._v(" 在线测试")]),t._v(" "),s("p",[s("img",{attrs:{src:"/aggr_config_test.png",alt:""}})]),t._v(" "),s("ul",[s("li",[t._v("支持在线实时测试")]),t._v(" "),s("li",[t._v("支持测试接口和正式接口隔离")]),t._v(" "),s("li",[t._v("支持返回上下文,可以查看整个执行过程中各个步骤及请求的输入与输出")]),t._v(" "),s("li",[t._v("支持保存历史测试记录")])]),t._v(" "),s("p",[s("img",{attrs:{src:"/aggr_config_test2.png",alt:""}})]),t._v(" "),s("p",[t._v("支持调试模式,在测试接口和正式接口均可使用,修改后重新发布可实时生效,在调试模式下会打印请求日志及报文,主要用于排查线上问题")]),t._v(" "),s("h2",{attrs:{id:"导入导出"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#导入导出"}},[t._v("#")]),t._v(" 导入导出")]),t._v(" "),s("p",[s("img",{attrs:{src:"/aggr_config_import_export.png",alt:""}})]),t._v(" "),s("p",[t._v("导入导出主要用于在各个环境间同步接口配置,在开发环境配置好后导到测试环境中测试,测试完后导到生产环境进行发布")]),t._v(" "),s("h2",{attrs:{id:"发布-下线和审核"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#发布-下线和审核"}},[t._v("#")]),t._v(" 发布|下线和审核")]),t._v(" "),s("p",[s("img",{attrs:{src:"/aggr_release_1.png",alt:""}})]),t._v(" "),s("p",[s("img",{attrs:{src:"/aggr_release_2.png",alt:""}})]),t._v(" "),s("p",[t._v("目前发布|下线申请有以上两个入口。")]),t._v(" "),s("p",[s("img",{attrs:{src:"/aggr_release_rollback1.png",alt:""}})]),t._v(" "),s("p",[s("img",{attrs:{src:"/aggr_release_rollback.png",alt:""}})]),t._v(" "),s("ul",[s("li",[t._v("批量发布:对发布单里的接口进行批量发布")]),t._v(" "),s("li",[t._v("批量回滚:对发布单里的接口进行批量回滚")]),t._v(" "),s("li",[t._v("发布:实时发布到网关")]),t._v(" "),s("li",[t._v("回滚:支持回滚到历史任何一个版本,可在发布历史里指定一个版本进行回滚")]),t._v(" "),s("li",[t._v("下线:从网关删除接口,在后台可以通过发布功能再次上线")])]),t._v(" "),s("h3",{attrs:{id:"发布流程说明"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#发布流程说明"}},[t._v("#")]),t._v(" 发布流程说明")]),t._v(" "),s("p",[t._v("申请发布、审核、发布和下线功能的权限可根据需要灵活分配给不同角色,如:开发人员只能申请发布,上级领导审核,运维或测试人员执行发布、回滚或下线。在开发、测试和预生产环境为了方便开发人员调试也可把申请发布、审核、发布和下线功能都分配给开发人员。")])])}),[],!1,null,null,null);a.default=e.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[9],{355:function(t,a,s){"use strict";s.r(a);var n=s(42),e=Object(n.a)({},(function(){var t=this,a=t.$createElement,s=t._self._c||a;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("h2",{attrs:{id:"创建服务"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#创建服务"}},[t._v("#")]),t._v(" 创建服务")]),t._v(" "),s("p",[s("img",{attrs:{src:"/aggr_newservice.png",alt:""}})]),t._v(" "),s("h2",{attrs:{id:"创建聚合接口"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#创建聚合接口"}},[t._v("#")]),t._v(" 创建聚合接口")]),t._v(" "),s("p",[s("img",{attrs:{src:"/aggr_newapi0.png",alt:""}}),t._v(" "),s("img",{attrs:{src:"/aggr_newapi.png",alt:""}})]),t._v(" "),s("h2",{attrs:{id:"配置输入"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#配置输入"}},[t._v("#")]),t._v(" 配置输入")]),t._v(" "),s("p",[s("img",{attrs:{src:"/aggr_config_input.png",alt:""}})]),t._v(" "),s("ul",[s("li",[t._v("配置输入的定义包括3部分:请求头、请求体和Query参数")]),t._v(" "),s("li",[t._v("基于JSON Schema规范")]),t._v(" "),s("li",[t._v("自带校验规则")]),t._v(" "),s("li",[t._v("支持自定义脚本实现复杂的逻辑校验")])]),t._v(" "),s("p",[t._v("JSON Schema规范,详见:")]),t._v(" "),s("p",[s("a",{attrs:{href:"http://json-schema.org/specification.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("http://json-schema.org/specification.html"),s("OutboundLink")],1)]),t._v(" "),s("p",[s("a",{attrs:{href:"http://json-schema.org/understanding-json-schema/",target:"_blank",rel:"noopener noreferrer"}},[t._v("http://json-schema.org/understanding-json-schema/"),s("OutboundLink")],1)]),t._v(" "),s("h2",{attrs:{id:"配置校验结果"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#配置校验结果"}},[t._v("#")]),t._v(" 配置校验结果")]),t._v(" "),s("p",[s("img",{attrs:{src:"/aggr_config_input_validate_result.png",alt:""}})]),t._v(" "),s("ul",[s("li",[t._v("校验不通过时,Fizz会把校验失败的原因(如:订单ID不能为空)放到上下文的validateMsg字段里")]),t._v(" "),s("li",[t._v("可以自定义返回给调用方的报文格式,如 msgCode, message")]),t._v(" "),s("li",[t._v("支持自定义响应头")]),t._v(" "),s("li",[t._v("支持自定义脚本处理校验结果")])]),t._v(" "),s("h2",{attrs:{id:"配置步骤"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#配置步骤"}},[t._v("#")]),t._v(" 配置步骤")]),t._v(" "),s("h3",{attrs:{id:"配置步骤的基础信息"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#配置步骤的基础信息"}},[t._v("#")]),t._v(" 配置步骤的基础信息")]),t._v(" "),s("p",[s("img",{attrs:{src:"/aggr_config_step1.png",alt:""}})]),t._v(" "),s("h3",{attrs:{id:"配置步骤的接口入出参"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#配置步骤的接口入出参"}},[t._v("#")]),t._v(" 配置步骤的接口入出参")]),t._v(" "),s("p",[s("img",{attrs:{src:"/aggr_config_step2.png",alt:""}})]),t._v(" "),s("h3",{attrs:{id:"步骤说明"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#步骤说明"}},[t._v("#")]),t._v(" 步骤说明")]),t._v(" "),s("ul",[s("li",[t._v("一个聚合接口可包含多个步骤")]),t._v(" "),s("li",[t._v("一个步骤可包含多个请求(即调用多个接口)")]),t._v(" "),s("li",[t._v("步骤间是串联顺序执行")]),t._v(" "),s("li",[t._v("一个步骤内的多个请求并行执行")])]),t._v(" "),s("h3",{attrs:{id:"数据转换"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#数据转换"}},[t._v("#")]),t._v(" 数据转换")]),t._v(" "),s("p",[t._v("支持配置固定值,引用值和脚本")]),t._v(" "),s("h4",{attrs:{id:"固定值"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#固定值"}},[t._v("#")]),t._v(" 固定值")]),t._v(" "),s("p",[s("img",{attrs:{src:"/aggr_config_step_mapping_1.png",alt:""}})]),t._v(" "),s("h4",{attrs:{id:"引用值"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#引用值"}},[t._v("#")]),t._v(" 引用值")]),t._v(" "),s("p",[s("img",{attrs:{src:"/aggr_config_step_mapping_2.png",alt:""}})]),t._v(" "),s("h4",{attrs:{id:"脚本"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#脚本"}},[t._v("#")]),t._v(" 脚本")]),t._v(" "),s("p",[s("img",{attrs:{src:"/aggr_config_step_mapping_3.png",alt:""}})]),t._v(" "),s("p",[s("img",{attrs:{src:"/aggr_config_step_mapping_4.png",alt:""}})]),t._v(" "),s("h4",{attrs:{id:"星号"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#星号"}},[t._v("#")]),t._v(" 星号 *")]),t._v(" "),s("p",[t._v("星号通配符可以接收一个返回对象类型的引用值,返回对象里的字段会合并到目标对象里")]),t._v(" "),s("p",[s("img",{attrs:{src:"/aggr_config_step_mapping_5.png",alt:""}})]),t._v(" "),s("p",[t._v('样例:userInfo = {"userName": "Fizz", "userID": 1234}')]),t._v(" "),s("h4",{attrs:{id:"优先级与覆盖顺序"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#优先级与覆盖顺序"}},[t._v("#")]),t._v(" 优先级与覆盖顺序")]),t._v(" "),s("p",[t._v("固定值 < 引用值 < 脚本 < 星号*")]),t._v(" "),s("p",[t._v("当一个字段配置了多种类型的值时按以上顺序覆盖,星号优先级最高")]),t._v(" "),s("h4",{attrs:{id:"引用值规范"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#引用值规范"}},[t._v("#")]),t._v(" 引用值规范")]),t._v(" "),s("div",{staticClass:"language-properties extra-class"},[s("pre",{pre:!0,attrs:{class:"language-properties"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 获取入参请求头aaa的值")]),t._v("\ninput.request.headers.aaa\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 获取入参请求体bbb字段的值")]),t._v("\ninput.request.body.bbb\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 获取入参URL Query参数fff字段的值")]),t._v("\ninput.request.params.fff\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 获取步骤1里request1的请求头ccc的值")]),t._v("\nstep1.request1.request.headers.ccc\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 获取步骤1里request1的响应体ddd的值")]),t._v("\nstep1.request1.response.body.ddd\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 获取步骤1结果里eee的值")]),t._v("\nstep1.result.eee\n\n")])])]),s("ul",[s("li",[t._v("支持单值引用,如:string,int等")]),t._v(" "),s("li",[t._v("支持对象类型的引用")])]),t._v(" "),s("p",[t._v("input: 表示调用方的输入数据,如H5页面提交上来的参数")]),t._v(" "),s("p",[t._v("stepN.requestN: 表示步骤N里调用接口N的相关参数")]),t._v(" "),s("p",[t._v("stepN.result: 表示步骤N的转换结果")]),t._v(" "),s("h4",{attrs:{id:"fallback与预处理条件"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#fallback与预处理条件"}},[t._v("#")]),t._v(" Fallback与预处理条件")]),t._v(" "),s("p",[s("img",{attrs:{src:"/aggr_config_step_fallback.png",alt:""}})]),t._v(" "),s("p",[t._v("Fallback:")]),t._v(" "),s("p",[t._v("当调用接口发生异常(如超时、网络或系统异常)可配置fallback方案:")]),t._v(" "),s("ul",[s("li",[t._v("Stop: 终止请求并立即返回")]),t._v(" "),s("li",[t._v("Continue: 继续后续的操作,且要设置默认的fallback json")])]),t._v(" "),s("p",[t._v("预处理: 根据条件判断是否要调用接口,脚本返回true时才调用接口")]),t._v(" "),s("h4",{attrs:{id:"配置步骤结果处理"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#配置步骤结果处理"}},[t._v("#")]),t._v(" 配置步骤结果处理")]),t._v(" "),s("p",[s("img",{attrs:{src:"/aggr_config_step_result.png",alt:""}})]),t._v(" "),s("ul",[s("li",[s("p",[t._v("支持对步骤里调用的每一个接口的返回结果做数据转换,如果配置数据转换规则原样返回并存储到上下文里供后续使用")])]),t._v(" "),s("li",[s("p",[t._v("支持对步骤里调用的一个或多个接口的返回结果做处理,并把处理完的结果存储到上下文里供后续使用,不配置则不处理")])])]),t._v(" "),s("h2",{attrs:{id:"配置输出"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#配置输出"}},[t._v("#")]),t._v(" 配置输出")]),t._v(" "),s("p",[s("img",{attrs:{src:"/aggr_config_output.png",alt:""}})]),t._v(" "),s("p",[t._v("配置返回给调用方的结果")]),t._v(" "),s("ul",[s("li",[t._v("支持配置响应头")]),t._v(" "),s("li",[t._v("支持配置响应体")]),t._v(" "),s("li",[t._v("支持自定脚本处理复杂的业务逻辑")])]),t._v(" "),s("h2",{attrs:{id:"脚本-2"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#脚本-2"}},[t._v("#")]),t._v(" 脚本")]),t._v(" "),s("p",[t._v("目前支持以下脚本语言:")]),t._v(" "),s("p",[t._v("Javascript (推荐) - ECMAScript 5标准")]),t._v(" "),s("p",[t._v("JS脚本只支持单函数,且函数名不可变,在创建脚本时系统会自动生成初始模板,模板里包含相关使用说明")]),t._v(" "),s("p",[s("img",{attrs:{src:"/aggr_config_script_1.png",alt:""}})]),t._v(" "),s("p",[t._v("Groovy")]),t._v(" "),s("p",[s("img",{attrs:{src:"/aggr_config_script_2.png",alt:""}})]),t._v(" "),s("h3",{attrs:{id:"common-js-提供了操作context上下文的便捷操作函数"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#common-js-提供了操作context上下文的便捷操作函数"}},[t._v("#")]),t._v(" common.js 提供了操作context上下文的便捷操作函数")]),t._v(" "),s("div",{staticClass:"language-javascript extra-class"},[s("pre",{pre:!0,attrs:{class:"language-javascript"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/**\n * context 上下文便捷操作函数\n *\n */")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" common "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/* *********** private function begin *********** */")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 获取上下文中客户端请求对象")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token function-variable function"}},[t._v("getInputReq")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token parameter"}},[t._v("ctx")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("ctx "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'input'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'input'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'request'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'input'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'request'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 获取上下文步骤中请求接口的请求对象")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token function-variable function"}},[t._v("getStepReq")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token parameter"}},[t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" stepName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" requestName")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("ctx "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("stepName "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("requestName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("stepName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("stepName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'requests'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("stepName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'requests'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("requestName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("stepName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'requests'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("requestName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'request'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("stepName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'requests'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("requestName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'request'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 获取上下文步骤中请求接口的响应对象")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token function-variable function"}},[t._v("getStepResp")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token parameter"}},[t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" stepName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" requestName")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("ctx "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("stepName "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("requestName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("stepName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("stepName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'requests'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("stepName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'requests'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("requestName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("stepName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'requests'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("requestName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'response'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("stepName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'requests'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("requestName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'response'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/* *********** private function end *********** */")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/* *********** input begin ************ */")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/**\n * 获取客户端请求头\n * @param {*} ctx 上下文 【必填】\n * @param {*} headerName 请求头字段名 【选填】,不传时返回所有请求头\n */")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token function-variable function"}},[t._v("getInputReqHeader")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token parameter"}},[t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" headerName")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" req "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("this")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getInputReq")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" headers "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" req"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'headers'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" headerName "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),t._v(" headers"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("headerName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" headers"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/**\n * 获取客户端URL请求参数(query string)\n * @param {*} ctx 上下文 【必填】\n * @param {*} paramName URL参数名 【选填】,不传时返回所有请求参数\n */")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token function-variable function"}},[t._v("getInputReqParam")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token parameter"}},[t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" paramName")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" req "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("this")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getInputReq")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" params "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" req"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'params'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" paramName "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),t._v(" params"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("paramName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" params"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/**\n * 获取客户端请求体\n * @param {*} ctx 上下文 【必填】\n * @param {*} field 字段名 【选填】,不传时返回整个请求体\n */")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token function-variable function"}},[t._v("getInputReqBody")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token parameter"}},[t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" field")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" req "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("this")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getInputReq")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" body "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" req"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'body'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" field "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),t._v(" body"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("field"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" body"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/**\n * 获取返回给客户端的响应头\n * @param {*} ctx 上下文 【必填】\n * @param {*} headerName 响应头字段名 【选填】,不传时返回所有响应头\n */")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token function-variable function"}},[t._v("getInputRespHeader")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token parameter"}},[t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" headerName")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" req "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("this")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getInputReq")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" headers "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" req"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'headers'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" headerName "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),t._v(" headers"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("headerName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" headers"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/**\n * 获取返回给客户端的响应体\n * @param {*} ctx 上下文 【必填】\n * @param {*} field 字段名 【选填】,不传时返回整个响应体\n */")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token function-variable function"}},[t._v("getInputRespBody")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token parameter"}},[t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" field")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" req "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("this")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getInputReq")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" body "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" req"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'body'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" field "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),t._v(" body"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("field"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" body"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/* *********** input begin ************ */")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/* *********** step request begin ************ */")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/**\n * 获取步骤中调用的接口的请求头\n * @param {*} ctx 上下文 【必填】\n * @param {*} stepName 步骤名【必填】\n * @param {*} requestName 请求的接口名 【必填】\n * @param {*} headerName 请求头字段名 【选填】,不传时返回所有请求头\n */")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token function-variable function"}},[t._v("getStepReqHeader")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token parameter"}},[t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" stepName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" requestName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" headerName")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" req "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("this")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getStepReq")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" stepName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" requestName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" headers "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" req"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'headers'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" headerName "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),t._v(" headers"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("headerName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" headers"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/**\n * 获取步骤中调用的接口的URL参数\n * @param {*} ctx 上下文 【必填】\n * @param {*} stepName 步骤名【必填】\n * @param {*} requestName 请求的接口名 【必填】\n * @param {*} paramName URL参数名 【选填】,不传时返回所有URL参数\n */")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token function-variable function"}},[t._v("getStepReqParam")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token parameter"}},[t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" stepName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" requestName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" paramName")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" req "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("this")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getStepReq")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" stepName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" requestName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" params "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" req"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'params'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" paramName "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),t._v(" params"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("paramName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" params"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/**\n * 获取步骤中调用的接口的请求体\n * @param {*} ctx 上下文 【必填】\n * @param {*} stepName 步骤名【必填】\n * @param {*} requestName 请求的接口名 【必填】\n * @param {*} field 字段名 【选填】,不传时返回整个请求体\n */")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token function-variable function"}},[t._v("getStepReqBody")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token parameter"}},[t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" stepName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" requestName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" field")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" req "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("this")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getStepReq")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" stepName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" requestName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" body "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" req"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'body'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" field "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),t._v(" body"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("field"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" body"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/**\n * 获取步骤中调用的接口的响应头\n * @param {*} ctx 上下文 【必填】\n * @param {*} stepName 步骤名【必填】\n * @param {*} requestName 请求的接口名 【必填】\n * @param {*} headerName 响应头字段名 【选填】,不传时返回所有响应头\n */")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token function-variable function"}},[t._v("getStepRespHeader")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token parameter"}},[t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" stepName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" requestName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" headerName")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" resp "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("this")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getStepResp")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" stepName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" requestName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" headers "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" resp"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'headers'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" headerName "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),t._v(" headers"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("headerName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" headers"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/**\n * 获取步骤中调用的接口的响应头\n * @param {*} ctx 上下文 【必填】\n * @param {*} stepName 步骤名【必填】\n * @param {*} requestName 请求的接口名 【必填】\n * @param {*} field 字段名 【选填】,不传时返回整个响应头\n */")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token function-variable function"}},[t._v("getStepRespBody")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token parameter"}},[t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" stepName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" requestName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" field")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" resp "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("this")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getStepResp")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" stepName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" requestName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" body "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" resp"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'body'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" field "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),t._v(" body"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("field"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" body"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/**\n * 获取步骤结果\n * @param {*} ctx 上下文 【必填】\n * @param {*} stepName 步骤名【必填】\n * @param {*} field 字段名 【选填】,不传时返回整个步骤结果对象\n */")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token function-variable function"}},[t._v("getStepResult")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token parameter"}},[t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" stepName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" field")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("ctx "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("stepName "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("stepName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" result "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("stepName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'result'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" field "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),t._v(" result"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("field"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" result"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/* *********** step request end ************ */")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n")])])]),s("h3",{attrs:{id:"context-js-数据结构"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#context-js-数据结构"}},[t._v("#")]),t._v(" context.js 数据结构")]),t._v(" "),s("div",{staticClass:"language-javascript extra-class"},[s("pre",{pre:!0,attrs:{class:"language-javascript"}},[s("code",[t._v("\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 上下文,用于保存客户输入输出和每个步骤的输入与输出结果")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" context "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 是否DEBUG模式")]),t._v("\n\tdebug"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),s("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("false")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n\t"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 各个操作的耗时")]),t._v("\n\telapsedTimes"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("actionName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("123")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 操作名称:耗时")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 客户输入和接口的返回结果")]),t._v("\n input"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n request"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n path"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('""')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n method"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"GET/POST"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n headers"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n body"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n params"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n response"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 聚合接口的响应")]),t._v("\n headers"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n body"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 步骤")]),t._v("\n step1"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n requests"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 接口1")]),t._v("\n request1"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 请求相关参数")]),t._v("\n request"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n url"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('""')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n method"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"GET/POST"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n headers"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n body"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 根据转换规则转换后的接口响应")]),t._v("\n response"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n headers"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n body"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 接口2")]),t._v("\n request2"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n request"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n url"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('""')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n method"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"GET/POST"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n headers"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n body"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n response"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n headers"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n body"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("//...")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 步骤结果")]),t._v("\n result"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n")])])]),s("h2",{attrs:{id:"异常处理"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#异常处理"}},[t._v("#")]),t._v(" 异常处理")]),t._v(" "),s("p",[t._v("当要在脚本里中止请求时可以通过以下方式来实现")]),t._v(" "),s("p",[s("img",{attrs:{src:"/aggr_config_exception.png",alt:""}})]),t._v(" "),s("p",[t._v("返回一个对象且这个对象包含一个_stopAndResponse等于true的属性,Fizz会终止后续的操作并把这个对象返回给调用方。")]),t._v(" "),s("h2",{attrs:{id:"重定向"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#重定向"}},[t._v("#")]),t._v(" 重定向")]),t._v(" "),s("p",[t._v("通过脚本可以实现重定向,脚本返回一个对象且这个对象同时包含_stopAndResponse=true和_redirectUrl属性,_redirectUrl的值为重定向的目标URL,Fizz会终止后续的操作并进行重定向。JavaScript脚本样例如下:")]),t._v(" "),s("p",[s("img",{attrs:{src:"/aggr_config_redirect.png",alt:""}})]),t._v(" "),s("h2",{attrs:{id:"配置路由"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#配置路由"}},[t._v("#")]),t._v(" 配置路由")]),t._v(" "),s("p",[t._v("至此服务编排的接口配置完成,但此时还不能通过网关访问接口,需要到网关管理-路由管理里配置路由")]),t._v(" "),s("p",[s("img",{attrs:{src:"/aggr_config_route.png",alt:""}})]),t._v(" "),s("h2",{attrs:{id:"在线测试"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#在线测试"}},[t._v("#")]),t._v(" 在线测试")]),t._v(" "),s("p",[s("img",{attrs:{src:"/aggr_config_test.png",alt:""}})]),t._v(" "),s("ul",[s("li",[t._v("支持在线实时测试")]),t._v(" "),s("li",[t._v("支持测试接口和正式接口隔离")]),t._v(" "),s("li",[t._v("支持返回上下文,可以查看整个执行过程中各个步骤及请求的输入与输出")]),t._v(" "),s("li",[t._v("支持保存历史测试记录")])]),t._v(" "),s("p",[s("img",{attrs:{src:"/aggr_config_test2.png",alt:""}})]),t._v(" "),s("p",[t._v("支持调试模式,在测试接口和正式接口均可使用,修改后重新发布可实时生效,在调试模式下会打印请求日志及报文,主要用于排查线上问题")]),t._v(" "),s("h2",{attrs:{id:"导入导出"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#导入导出"}},[t._v("#")]),t._v(" 导入导出")]),t._v(" "),s("p",[s("img",{attrs:{src:"/aggr_config_import_export.png",alt:""}})]),t._v(" "),s("p",[t._v("导入导出主要用于在各个环境间同步接口配置,在开发环境配置好后导到测试环境中测试,测试完后导到生产环境进行发布")]),t._v(" "),s("h2",{attrs:{id:"发布-下线和审核"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#发布-下线和审核"}},[t._v("#")]),t._v(" 发布|下线和审核")]),t._v(" "),s("p",[s("img",{attrs:{src:"/aggr_release_1.png",alt:""}})]),t._v(" "),s("p",[s("img",{attrs:{src:"/aggr_release_2.png",alt:""}})]),t._v(" "),s("p",[t._v("目前发布|下线申请有以上两个入口。")]),t._v(" "),s("p",[s("img",{attrs:{src:"/aggr_release_rollback1.png",alt:""}})]),t._v(" "),s("p",[s("img",{attrs:{src:"/aggr_release_rollback.png",alt:""}})]),t._v(" "),s("ul",[s("li",[t._v("批量发布:对发布单里的接口进行批量发布")]),t._v(" "),s("li",[t._v("批量回滚:对发布单里的接口进行批量回滚")]),t._v(" "),s("li",[t._v("发布:实时发布到网关")]),t._v(" "),s("li",[t._v("回滚:支持回滚到历史任何一个版本,可在发布历史里指定一个版本进行回滚")]),t._v(" "),s("li",[t._v("下线:从网关删除接口,在后台可以通过发布功能再次上线")])]),t._v(" "),s("h3",{attrs:{id:"发布流程说明"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#发布流程说明"}},[t._v("#")]),t._v(" 发布流程说明")]),t._v(" "),s("p",[t._v("申请发布、审核、发布和下线功能的权限可根据需要灵活分配给不同角色,如:开发人员只能申请发布,上级领导审核,运维或测试人员执行发布、回滚或下线。在开发、测试和预生产环境为了方便开发人员调试也可把申请发布、审核、发布和下线功能都分配给开发人员。")])])}),[],!1,null,null,null);a.default=e.exports}}]); \ No newline at end of file diff --git a/docs/assets/js/app.86b5ae26.js b/docs/assets/js/app.60575df2.js similarity index 87% rename from docs/assets/js/app.86b5ae26.js rename to docs/assets/js/app.60575df2.js index ee18dc9..2c5a1d8 100644 --- a/docs/assets/js/app.86b5ae26.js +++ b/docs/assets/js/app.60575df2.js @@ -1,4 +1,4 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[0],[]]);!function(t){function e(e){for(var r,a,u=e[0],c=e[1],s=e[2],f=0,p=[];f0?o(r(t),9007199254740991):0}},function(t,e){var n=Array.isArray;t.exports=n},function(t,e,n){var r=n(31),o=n(23);t.exports=function(t){return r(o(t))}},function(t,e,n){var r=n(140),o="object"==typeof self&&self&&self.Object===Object&&self,i=r||o||Function("return this")();t.exports=i},function(t,e,n){var r=n(6),o=n(1),i=n(7),a=Object.defineProperty,u={},c=function(t){throw t};t.exports=function(t,e){if(i(u,t))return u[t];e||(e={});var n=[][t],s=!!i(e,"ACCESSORS")&&e.ACCESSORS,l=i(e,0)?e[0]:c,f=i(e,1)?e[1]:void 0;return u[t]=!!n&&!o((function(){if(s&&!r)return!0;var t={length:-1};s?a(t,1,{enumerable:!0,get:c}):t[1]=1,n.call(t,l,f)}))}},function(t,e){var n={}.toString;t.exports=function(t){return n.call(t).slice(8,-1)}},function(t,e,n){var r=n(110),o=n(3),i=function(t){return"function"==typeof t?t:void 0};t.exports=function(t,e){return arguments.length<2?i(r[t])||i(o[t]):r[t]&&r[t][e]||o[t]&&o[t][e]}},function(t,e){t.exports=!1},function(t,e){t.exports=function(t){if("function"!=typeof t)throw TypeError(String(t)+" is not a function");return t}},function(t,e,n){var r=n(220),o=n(223);t.exports=function(t,e){var n=o(t,e);return r(n)?n:void 0}},function(t,e){t.exports=function(t){if(null==t)throw TypeError("Can't call method on "+t);return t}},function(t,e,n){"use strict";var r=n(0),o=n(29).filter,i=n(51),a=n(17),u=i("filter"),c=a("filter");r({target:"Array",proto:!0,forced:!u||!c},{filter:function(t){return o(this,t,arguments.length>1?arguments[1]:void 0)}})},function(t,e,n){var r=n(6),o=n(75),i=n(32),a=n(15),u=n(44),c=n(7),s=n(105),l=Object.getOwnPropertyDescriptor;e.f=r?l:function(t,e){if(t=a(t),e=u(e,!0),s)try{return l(t,e)}catch(t){}if(c(t,e))return i(!o.f.call(t,e),t[e])}},function(t,e){t.exports=function(t){return null!=t&&"object"==typeof t}},function(t,e,n){"use strict";var r=n(128).charAt,o=n(28),i=n(111),a=o.set,u=o.getterFor("String Iterator");i(String,"String",(function(t){a(this,{type:"String Iterator",string:String(t),index:0})}),(function(){var t,e=u(this),n=e.string,o=e.index;return o>=n.length?{value:void 0,done:!0}:(t=r(n,o),e.index+=t.length,{value:t,done:!1})}))},function(t,e,n){var r,o,i,a=n(180),u=n(3),c=n(4),s=n(11),l=n(7),f=n(48),p=n(34),d=u.WeakMap;if(a){var h=new d,v=h.get,g=h.has,m=h.set;r=function(t,e){return m.call(h,t,e),e},o=function(t){return v.call(h,t)||{}},i=function(t){return g.call(h,t)}}else{var y=f("state");p[y]=!0,r=function(t,e){return s(t,y,e),e},o=function(t){return l(t,y)?t[y]:{}},i=function(t){return l(t,y)}}t.exports={set:r,get:o,has:i,enforce:function(t){return i(t)?o(t):r(t,{})},getterFor:function(t){return function(e){var n;if(!c(e)||(n=o(e)).type!==t)throw TypeError("Incompatible receiver, "+t+" required");return n}}}},function(t,e,n){var r=n(50),o=n(31),i=n(12),a=n(13),u=n(127),c=[].push,s=function(t){var e=1==t,n=2==t,s=3==t,l=4==t,f=6==t,p=5==t||f;return function(d,h,v,g){for(var m,y,b=i(d),_=o(b),x=r(h,v,3),w=a(_.length),O=0,S=g||u,j=e?S(d,w):n?S(d,0):void 0;w>O;O++)if((p||O in _)&&(y=x(m=_[O],O,b),t))if(e)j[O]=y;else if(y)switch(t){case 3:return!0;case 5:return m;case 6:return O;case 2:c.call(j,m)}else if(l)return!1;return f?-1:s||l?l:j}};t.exports={forEach:s(0),map:s(1),filter:s(2),some:s(3),every:s(4),find:s(5),findIndex:s(6)}},function(t,e,n){var r=n(39),o=n(205),i=n(206),a=r?r.toStringTag:void 0;t.exports=function(t){return null==t?void 0===t?"[object Undefined]":"[object Null]":a&&a in Object(t)?o(t):i(t)}},function(t,e,n){var r=n(1),o=n(18),i="".split;t.exports=r((function(){return!Object("z").propertyIsEnumerable(0)}))?function(t){return"String"==o(t)?i.call(t,""):Object(t)}:Object},function(t,e){t.exports=function(t,e){return{enumerable:!(1&t),configurable:!(2&t),writable:!(4&t),value:e}}},function(t,e,n){var r,o=n(5),i=n(179),a=n(73),u=n(34),c=n(109),s=n(70),l=n(48),f=l("IE_PROTO"),p=function(){},d=function(t){return" +

coming soon

上次更新: 2020-9-8 15:3
+ diff --git a/docs/guide/aggregate/configuration.html b/docs/guide/aggregate/configuration.html index da93a75..3bb2aa4 100644 --- a/docs/guide/aggregate/configuration.html +++ b/docs/guide/aggregate/configuration.html @@ -7,7 +7,7 @@ - + @@ -23,7 +23,7 @@ 使用文档
查看源码 -

# 创建服务

# 创建聚合接口

# 配置输入

  • 配置输入的定义包括3部分:请求头、请求体和Query参数
  • 基于JSON Schema规范
  • 自带校验规则
  • 支持自定义脚本实现复杂的逻辑校验

JSON Schema规范,详见:

http://json-schema.org/specification.html

http://json-schema.org/understanding-json-schema/

# 配置校验结果

  • 校验不通过时,Fizz会把校验失败的原因(如:订单ID不能为空)放到上下文的validateMsg字段里
  • 可以自定义返回给调用方的报文格式,如 msgCode, message
  • 支持自定义响应头
  • 支持自定义脚本处理校验结果

# 配置步骤

# 配置步骤的基础信息

# 配置步骤的接口入出参

# 步骤说明

  • 一个聚合接口可包含多个步骤
  • 一个步骤可包含多个请求(即调用多个接口)
  • 步骤间是串联顺序执行
  • 一个步骤内的多个请求并行执行

# 数据转换

支持配置固定值,引用值和脚本

# 固定值

# 引用值

# 脚本

# 星号 *

星号通配符可以接收一个返回对象类型的引用值,返回对象里的字段会合并到目标对象里

样例:userInfo = {"userName": "Fizz", "userID": 1234}

# 优先级与覆盖顺序

固定值 < 引用值 < 脚本 < 星号*

当一个字段配置了多种类型的值时按以上顺序覆盖,星号优先级最高

# 引用值规范

# 获取入参请求头aaa的值
+        

# 创建服务

# 创建聚合接口

# 配置输入

  • 配置输入的定义包括3部分:请求头、请求体和Query参数
  • 基于JSON Schema规范
  • 自带校验规则
  • 支持自定义脚本实现复杂的逻辑校验

JSON Schema规范,详见:

http://json-schema.org/specification.html

http://json-schema.org/understanding-json-schema/

# 配置校验结果

  • 校验不通过时,Fizz会把校验失败的原因(如:订单ID不能为空)放到上下文的validateMsg字段里
  • 可以自定义返回给调用方的报文格式,如 msgCode, message
  • 支持自定义响应头
  • 支持自定义脚本处理校验结果

# 配置步骤

# 配置步骤的基础信息

# 配置步骤的接口入出参

# 步骤说明

  • 一个聚合接口可包含多个步骤
  • 一个步骤可包含多个请求(即调用多个接口)
  • 步骤间是串联顺序执行
  • 一个步骤内的多个请求并行执行

# 数据转换

支持配置固定值,引用值和脚本

# 固定值

# 引用值

# 脚本

# 星号 *

星号通配符可以接收一个返回对象类型的引用值,返回对象里的字段会合并到目标对象里

样例:userInfo = {"userName": "Fizz", "userID": 1234}

# 优先级与覆盖顺序

固定值 < 引用值 < 脚本 < 星号*

当一个字段配置了多种类型的值时按以上顺序覆盖,星号优先级最高

# 引用值规范

# 获取入参请求头aaa的值
 input.request.headers.aaa
 
 # 获取入参请求体bbb字段的值
@@ -292,7 +292,7 @@ step1.result.eee
   }
 };
 
-

# 异常处理

当要在脚本里中止请求时可以通过以下方式来实现

返回一个对象且这个对象包含一个_stopAndResponse等于true的属性,Fizz会终止后续的操作并把这个对象返回给调用方。

# 配置路由

至此服务编排的接口配置完成,但此时还不能通过网关访问接口,需要到网关管理-路由管理里配置路由

# 在线测试

  • 支持在线实时测试
  • 支持测试接口和正式接口隔离
  • 支持返回上下文,可以查看整个执行过程中各个步骤及请求的输入与输出
  • 支持保存历史测试记录

支持调试模式,在测试接口和正式接口均可使用,修改后重新发布可实时生效,在调试模式下会打印请求日志及报文,主要用于排查线上问题

# 导入导出

导入导出主要用于在各个环境间同步接口配置,在开发环境配置好后导到测试环境中测试,测试完后导到生产环境进行发布

# 发布|下线和审核

目前发布|下线申请有以上两个入口。

  • 批量发布:对发布单里的接口进行批量发布
  • 批量回滚:对发布单里的接口进行批量回滚
  • 发布:实时发布到网关
  • 回滚:支持回滚到历史任何一个版本,可在发布历史里指定一个版本进行回滚
  • 下线:从网关删除接口,在后台可以通过发布功能再次上线

# 发布流程说明

申请发布、审核、发布和下线功能的权限可根据需要灵活分配给不同角色,如:开发人员只能申请发布,上级领导审核,运维或测试人员执行发布、回滚或下线。在开发、测试和预生产环境为了方便开发人员调试也可把申请发布、审核、发布和下线功能都分配给开发人员。

上次更新: 2020-11-9 11:50

# 异常处理

当要在脚本里中止请求时可以通过以下方式来实现

返回一个对象且这个对象包含一个_stopAndResponse等于true的属性,Fizz会终止后续的操作并把这个对象返回给调用方。

# 重定向

通过脚本可以实现重定向,脚本返回一个对象且这个对象同时包含_stopAndResponse=true和_redirectUrl属性,_redirectUrl的值为重定向的目标URL,Fizz会终止后续的操作并进行重定向。JavaScript脚本样例如下:

# 配置路由

至此服务编排的接口配置完成,但此时还不能通过网关访问接口,需要到网关管理-路由管理里配置路由

# 在线测试

  • 支持在线实时测试
  • 支持测试接口和正式接口隔离
  • 支持返回上下文,可以查看整个执行过程中各个步骤及请求的输入与输出
  • 支持保存历史测试记录

支持调试模式,在测试接口和正式接口均可使用,修改后重新发布可实时生效,在调试模式下会打印请求日志及报文,主要用于排查线上问题

# 导入导出

导入导出主要用于在各个环境间同步接口配置,在开发环境配置好后导到测试环境中测试,测试完后导到生产环境进行发布

# 发布|下线和审核

目前发布|下线申请有以上两个入口。

  • 批量发布:对发布单里的接口进行批量发布
  • 批量回滚:对发布单里的接口进行批量回滚
  • 发布:实时发布到网关
  • 回滚:支持回滚到历史任何一个版本,可在发布历史里指定一个版本进行回滚
  • 下线:从网关删除接口,在后台可以通过发布功能再次上线

# 发布流程说明

申请发布、审核、发布和下线功能的权限可根据需要灵活分配给不同角色,如:开发人员只能申请发布,上级领导审核,运维或测试人员执行发布、回滚或下线。在开发、测试和预生产环境为了方便开发人员调试也可把申请发布、审核、发布和下线功能都分配给开发人员。

上次更新: 2020-11-18 15:16
- + diff --git a/docs/guide/aggregate/index.html b/docs/guide/aggregate/index.html index 0ee3638..80176f7 100644 --- a/docs/guide/aggregate/index.html +++ b/docs/guide/aggregate/index.html @@ -7,7 +7,7 @@ - + @@ -23,7 +23,7 @@ 使用文档 查看源码 -

# 什么是服务编排

服务编排主要基于现有的业务微服务使用在线配置的方式快速的生成一个聚合接口。

特点: 在线API设计、在线测试、快速开发

# 举例说明

订单详情页面需要展示订单信息、商品信息和用户信息。可通过配置的方式生成一个接口先后调用底层微服务的订单详情接口、商品信息接口和用户信息接口,再从这3个接口的返回结果里提取需要的字段返回给前端页面。

# 服务编排架构

# 适用场景

# 前端

1、一个页面调用多个接口时,可以编排好返回聚合结果,提高页面数据的加载速度

2、移动设备计算能力有限,可以把数据计算或业务处理逻辑放到服务端完成,加快页面响应

# 后端

1、替换应用层的聚合接口,减少应用层的胶水代码

2、快速生成透传数据类型的接口

3、数据转换和映射

上次更新: 2020-11-9 11:50
- + diff --git a/docs/guide/aggregate/overview.html b/docs/guide/aggregate/overview.html index a9d9a0f..27ab75a 100644 --- a/docs/guide/aggregate/overview.html +++ b/docs/guide/aggregate/overview.html @@ -7,7 +7,7 @@ - + @@ -23,7 +23,7 @@ 使用文档 查看源码 -

1.创建服务

此服务是一个分组的概念,可以包含多个聚合接口,类似于微服务体系里的服务

2.创建服务编排接口

3.开通网关白名单和配置访问策略和插件

4.测试服务编排接口

5.发布接口

界面总览

上次更新: 2020-11-9 11:50
- + diff --git a/docs/guide/benchmark/index.html b/docs/guide/benchmark/index.html index c8edd58..f29e88f 100644 --- a/docs/guide/benchmark/index.html +++ b/docs/guide/benchmark/index.html @@ -7,7 +7,7 @@ - + @@ -23,7 +23,7 @@ 使用文档 查看源码 -

# 基准测试结果

我们将Fizz与Spring官方spring-cloud-gateway进行比较,使用相同的环境和条件,测试对象均为单个节点。

产品 QPS 90% Latency(ms)
直接访问后端服务 9087.46 10.76
fizz-gateway 5927.13 19.86
spring-cloud-gateway 5044.04 22.91

# 基准测试详情

# 硬件环境

后端服务所在服务器:

4核8G内存

Intel(R) Xeon(R) CPU X5675 @ 3.07GHz * 4

Linux version 3.10.0-327.el7.x86_64

节点所在服务器:

4核8G内存

Intel(R) Xeon(R) CPU X5675 @ 3.07GHz * 4

Linux version 3.10.0-327.el7.x86_64

压测程序所在服务器:

4核8G内存

Intel(R) Xeon(R) CPU X5675 @ 3.07GHz * 4

Linux version 3.10.0-327.el7.x86_64

# 压测工具

压测软件:wrk

并发连接: 100

# 压测结果截图

- + diff --git a/docs/guide/index.html b/docs/guide/index.html index ac45d19..2d3f6bd 100644 --- a/docs/guide/index.html +++ b/docs/guide/index.html @@ -7,7 +7,7 @@ - + @@ -23,7 +23,7 @@ 使用文档 查看源码 -
上次更新: 2020-7-31 17:12
- +
上次更新: 2020-7-31 17:12
+ diff --git a/docs/guide/installation/index.html b/docs/guide/installation/index.html index 7dad870..564c732 100644 --- a/docs/guide/installation/index.html +++ b/docs/guide/installation/index.html @@ -7,7 +7,7 @@ - + @@ -23,7 +23,7 @@ 使用文档 查看源码 -

# 安装依赖

安装以下依赖软件:

  • Redis 2.8或以上版本
  • MySQL 5.7或以上版本
  • Apollo配置中心 (可选)
  • Eureka服务注册中心

# 安装MySQL

  • 操作系统 CentOS 6.5
  • MySQL 5.7.30
  1. 下载MySQL
wget https://downloads.mysql.com/archives/get/p/23/file/mysql-5.7.30-1.el6.x86_64.rpm-bundle.tar
+        

# 安装依赖

安装以下依赖软件:

  • Redis 2.8或以上版本
  • MySQL 5.7或以上版本
  • Apollo配置中心 (可选)
  • Eureka服务注册中心

# 安装MySQL

  • 操作系统 CentOS 6.5
  • MySQL 5.7.30
  1. 下载MySQL
wget https://downloads.mysql.com/archives/get/p/23/file/mysql-5.7.30-1.el6.x86_64.rpm-bundle.tar
 
  1. 解压
tar -xvf mysql-5.7.30-1.el6.x86_64.rpm-bundle.tar
 
  1. 安装
sudo yum install mysql-community-{server,client,common,libs}-*
 
  1. 启动
sudo service mysqld start
@@ -101,6 +101,6 @@ export JAVA_HOME JRE_HOME PATH CLASSPATH
       
       →
     

- + diff --git a/docs/guide/intro/index.html b/docs/guide/intro/index.html index 8013d9d..c41e4a9 100644 --- a/docs/guide/intro/index.html +++ b/docs/guide/intro/index.html @@ -7,7 +7,7 @@ - + @@ -23,11 +23,11 @@ 使用文档 查看源码 -

# 什么是Fizz网关

A Managerment API Gateway in Java . Fizz Gateway 是一个基于 Java开发的微服务网关,能够实现热服务编排、自动授权选择、线上服务脚本编码、在线测试、高性能路由、API审核管理等目的,拥有强大的自定义插件系统可以自行扩展,并且提供友好的图形化配置界面,能够快速帮助企业进行API服务治理、减少中间层胶水代码以及降低编码投入、提高 API 服务的稳定性和安全性。

# Fizz的设计

# 产品特性

  • 集群管理:Fizz网关节点是无状态的,配置信息自动同步,支持节点水平拓展和多集群部署。
  • 服务编排:支持热服务编排能力,支持前后端编码,随时随地更新API。
  • 负载均衡:支持round-robin负载均衡。
  • 服务发现:支持从Eureka注册中心发现后端服务器。
  • 配置中心:支持接入apollo配置中心。
  • HTTP反向代理:隐藏真实后端服务,支持 Rest API反向代理。
  • 访问策略:支持不同策略访问不同的API、配置不同的鉴权等。
  • IP黑白名单:支持配置IP黑白名单。
  • 自定义插件:强大的插件机制支持自由扩展。
  • 可扩展:简单易用的插件机制方便扩展功能。
  • 高性能:性能在众多网关之中表现优异。
  • 版本控制:支持操作的发布和多次回滚。
  • 管理后台:通过管理后台界面对网关集群进行各项配置。
上次更新: 2020-11-9 11:50
- + diff --git a/docs/guide/manager/manager_aggregate.html b/docs/guide/manager/manager_aggregate.html index 2b3b80f..f6fb035 100644 --- a/docs/guide/manager/manager_aggregate.html +++ b/docs/guide/manager/manager_aggregate.html @@ -7,7 +7,7 @@ - + @@ -23,7 +23,7 @@ 使用文档 查看源码 -

# 概述

接口列表功能用于维护聚合接口,聚合接口从外部调用方角度看是一个简单的接口,通过入参请求获取响应结果,内部实现会调用多个底层后端服务,将多个调用结果聚合转换成外部调用方想要的数据格式,更多详情请查看服务编排介绍,下面介绍接口列表功能的操作。

# 接口列表

菜单位置:服务编排 > 接口列表。点击菜单后进入接口列表页面,如图所示。

manager_aggregate_list_query

# 新增接口

点击 新增 按钮弹出新增窗口,如图所示。

manager_aggregate_add_1

# 基础信息

manager_aggregate_add_2

所属服务:接口所属服务,更多详情请查看服务管理功能介绍,必选;

接口名:接口名称,用于展示使用,长度不能超过200个字符,必填;

方法:接口请求方法类型,可选GET|POST,必选;

路径:接口请求路径后缀,长度不能超过2000个字符,必填;

开发人员:接口对应负责的开发人员,长度不能超过200个字符;

描述:接口功能描述,长度不能超过2000个字符;

举个例子,所属服务设置my-test-service,方法设置POST,路径设置test-aggregate-post,对应的聚合接口请求为 POST http://{Fizz网关ip地址}:{port端口}/proxy/my-test-service/test-aggregate-post。

# 配置输入

聚合接口的入参大部分是通过JSON Schema来定义的,下面先简单地介绍下JSON Schema。

# JSON Schema介绍

JSON Schema实际上也是JSON数据,用于标注和验证JSON文档,可以类比于XML Schema,当前最新版本2019-09。

作为普通用户,我们并不需要去了解JSON Schema的规范内容,只要能够构建JSON Schema即可。

要理解JSON Schema,首先要理解什么是JSON。JSON是JavaScript Object Notation的缩写,一种简单的数据交换格式。最初JSON是基于JavaScript,广泛的应用于万维网。由于其简洁和清晰的层次结构、易于人阅读等特性,使得越来越多的场景下被采用。

JSON包含以下数据结构:

- + diff --git a/docs/guide/manager/manager_aggregate_approve.html b/docs/guide/manager/manager_aggregate_approve.html index a3e9c89..505745d 100644 --- a/docs/guide/manager/manager_aggregate_approve.html +++ b/docs/guide/manager/manager_aggregate_approve.html @@ -7,7 +7,7 @@ - + @@ -23,7 +23,7 @@ 使用文档 查看源码 -

# 概述

聚合接口的发布|下线操作需要提交发布|下线申请,审核通过后申请人才能执行发布|下线操作。待审核功能用于审核发布|下线申请,下面介绍待审核功能。

# 审核列表

菜单位置:发布申请 > 待审核。点击菜单后进入审核列表页面,如图所示。

manager_aggregate_approve_list_query

# 审核操作

点击 查看 按钮可以查看发布|下线申请详情,详情页中可执行审核操作。

申请列表页提供快速审核操作,点击 审核 按钮后弹出审核确认窗口,如图所示。

manager_aggregate_approve_op_1

manager_aggregate_approve_op_2

审核结果:勾选通过,审核后申请能可执行申请的操作;勾选不通过,审核后申请失败,申请人不能执行申请的操作。

审核后申请人会收到审核结果邮件通知,如下图是审核通过的邮件通知。

manager_aggregate_approve_op_3

上次更新: 2020-11-9 11:50
- + diff --git a/docs/guide/manager/manager_aggregate_approve_op_log.html b/docs/guide/manager/manager_aggregate_approve_op_log.html index 7afd272..3ecf34f 100644 --- a/docs/guide/manager/manager_aggregate_approve_op_log.html +++ b/docs/guide/manager/manager_aggregate_approve_op_log.html @@ -7,7 +7,7 @@ - + @@ -23,7 +23,7 @@ 使用文档 查看源码 -

# 概述

管理后台记录了发布|下线申请的审核操作日志,审核日志功能提供界面查询后台记录的审核操作日志。

# 审核日志列表

菜单位置:发布申请 > 审核日志。点击菜单后进入审核日志列表页面,如图所示。

manager_aggregate_approve_op_log_list_query

# 审核日志详情

点击 查看 按钮弹出审核日志详情页面,如图所示。

manager_aggregate_approve_op_log_detail_1

manager_aggregate_approve_op_log_detail_2

上次更新: 2020-11-9 11:50
- + diff --git a/docs/guide/manager/manager_aggregate_my_apply.html b/docs/guide/manager/manager_aggregate_my_apply.html index 4a40314..9fe7b7b 100644 --- a/docs/guide/manager/manager_aggregate_my_apply.html +++ b/docs/guide/manager/manager_aggregate_my_apply.html @@ -7,7 +7,7 @@ - + @@ -23,7 +23,7 @@ 使用文档 查看源码 -

# 概述

聚合接口的发布|下线操作需要提交发布|下线申请,审核通过后申请人才能执行发布|下线操作。我的申请功能用于发布|下线申请过程的相关操作,下面介绍我的申请功能。

# 申请列表

菜单位置:发布申请 > 我的申请。点击菜单后进入申请列表页面,如图所示。

manager_aggregate_my_apply_list_query

# 申请撤回

对于已提交但未被审核的申请可执行撤回操作,点击 撤回 按钮弹出确认窗口,如图所示。

manager_aggregate_my_apply_revoke_1

点击 确定 按钮后确认撤回申请,如图所示。

manager_aggregate_my_apply_revoke_2

撤回后审核人会收到邮箱提醒无需再处理该申请,如图所示。

manager_aggregate_my_apply_revoke_3

撤回后可对申请重新进行编辑后再次提交,点击 编辑 按钮后弹出编辑窗口,如图所示。

manager_aggregate_my_apply_revoke_4

点击 确定 按钮后再次提交申请,如图所示。

manager_aggregate_my_apply_revoke_5

# 申请详情

点击 查看 按钮查看申请详情。

manager_aggregate_my_apply_detail_1

manager_aggregate_my_apply_detail_2

操作日志记录该申请的所有操作,包括申请提交、申请撤回、申请重新提交、审核不通过、审核通过、修改审核人、接口发布、接口下线 、接口回滚、接口撤回。

待审核状态申请可以更换审核人,点击 修改审核人 按钮后弹出修改审核人窗口,如图所示。

manager_aggregate_my_apply_detail_3

重新选择审核人后点击 确定 按钮,修改审核人完成。

修改后原审核人会收到邮件提醒无须再处理该申请。

修改后新的审核人会收到邮件提醒需要处理该申请。

审核通过后可以对接口进行发布操作,如图所示。

manager_aggregate_my_apply_detail_4

批量发布:对申请内的接口批量发布推送到Fizz网关。

批量回滚:对申请内的接口批量回滚到上一个版本,当发布后接口异常时该操作相当有用。

对于申请通过后又无须操作的接口可以执行撤回操作,撤回接口时必须填写备注信息用于回溯查询,如图所示。

manager_aggregate_my_apply_detail_5

manager_aggregate_my_apply_detail_6

上次更新: 2020-11-9 11:50
- + diff --git a/docs/guide/manager/manager_aggregate_op_log.html b/docs/guide/manager/manager_aggregate_op_log.html index 4e76b1d..73b1cc1 100644 --- a/docs/guide/manager/manager_aggregate_op_log.html +++ b/docs/guide/manager/manager_aggregate_op_log.html @@ -7,7 +7,7 @@ - + @@ -23,7 +23,7 @@ 使用文档 查看源码 -

# 概述

管理后台记录了聚合接口的新增、修改、发布、下线、回滚、删除操作日志,通过查看操作日志可以清楚地掌握接口的操作轨迹。操作日志功能提供界面查询聚合接口的操作日志。

# 操作日志列表

菜单位置:服务编排 > 操作日志。点击菜单后进入操作日志列表页面,如图所示。

manager_aggregate_op_log_list_query

# 查看日志详情

点击 查看 按钮弹出操作日志详情页面,如图所示。

manager_aggregate_op_log_detail_1

manager_aggregate_op_log_detail_2

上次更新: 2020-11-9 11:50
- + diff --git a/docs/guide/manager/manager_api_auth.html b/docs/guide/manager/manager_api_auth.html index aa47201..3d8e4f2 100644 --- a/docs/guide/manager/manager_api_auth.html +++ b/docs/guide/manager/manager_api_auth.html @@ -7,7 +7,7 @@ - + @@ -23,7 +23,7 @@ 使用文档 查看源码 -

# 概述

路由管理功能用于维护网关的路由规则,支持按请求路径转发、转发到指定后端服务两种转发规则,支持插件配置。下面介绍路由管理的操作。

# 路由列表

菜单位置:网关管理 > 路由管理。点击菜单后进入路由列表页面,如图所示。

manager_api_auth_list_query

# 新增路由

点击 新增 按钮弹出新增窗口,如图所示。

manager_api_auth_add_1

manager_api_auth_add_2

网关分组:选取路由关联的网关分组,只有属于所选分组的网关实例路由规则才会生效,必选;

服务:网关的请求路径格式为 http://{ip}:{port}/proxy/{service}{apiPath},服务对应{service}段,当 转发 选择 按请求路径转发 时服务需要是聚合配置的服务或者是Eureka注册的服务,当 转发 选择 转发到指定后端服务 时服务不需要是实际存在的服务,只用于路径匹配使用,长度不能超过50个字符,必填;

API方法:请求的method类型,可选GET|POST;

API Path:网关的请求路径格式为 http://{ip}:{port}/proxy/{service}{apiPath},API Path对应{apiPath}段,使用前缀匹配原则,例如"/api/"将匹配"/api/"、"/api/1"、"/api/1/1"等路径;

应用:选取路由关联的应用,网关使用选取应用的信息进行鉴权,更多详情请查看appID管理功能介绍;

访问:可选允许|禁止,必选;

转发:可选按请求路径转发|转发到指定后端服务,当选择 按请求路径转发 时,请求会按请求路径转发,例如网关请求 http://{ip}:{port}/proxy/my-service/api-path 将转发到 http://my-service/api-path;当选择 转发到指定后端服务 时,需要添加转发到的后端服务URL,请求会转发到配置的后端服务,例如配置了服务为 my-service,API Path为空,后端服务URL为 http://127.0.0.1:8080/forward-service/,网关请求 http://{ip}:{port}/proxy/my-service/api-path 将转发到 http://127.0.0.1:8080/forward-service/api-path。

点击 添加插件 按钮为路由添加插件,如图所示。

manager_api_auth_add_3

配置插件路由级别的自定义配置,表单界面来自于插件的表单定义,更多详情请查看插件管理功能介绍。

manager_api_auth_add_4

配置完成后点击 保存 按钮保存路由规则。

manager_api_auth_add_5

# 编辑路由

点击 编辑 按钮弹出编辑窗口,如图所示。

manager_api_auth_edit_1

manager_api_auth_edit_2

# 删除路由

点击 删除 按钮弹出删除确认窗口,如图所示。

manager_api_auth_delete_1

manager_api_auth_delete_2

上次更新: 2020-11-9 11:50
- + diff --git a/docs/guide/manager/manager_app_id.html b/docs/guide/manager/manager_app_id.html index 980c494..4757b96 100644 --- a/docs/guide/manager/manager_app_id.html +++ b/docs/guide/manager/manager_app_id.html @@ -7,7 +7,7 @@ - + @@ -23,7 +23,7 @@ 使用文档 查看源码 -

# 概述

appID管理功能维护应用鉴权信息,可配置是否启用签名、是否启用IP白名单,AppID级别的自定义配置供自定义插件使用。appID用于在路由管理配置中关联路由规则,当对应路由规则触发时会对应用进行鉴权。

# appID列表

菜单位置:网关管理 > appID管理。点击菜单后进入appID列表页面,如图所示。

manager_app_id_list_query

# 新增appID

点击 新增 按钮弹出新增窗口,如图所示。

manager_app_id_add_1

manager_app_id_add_2

appID:第三方应用唯一标识,长度不能超过64个字符,必填;

应用名:第三方应用名称,长度不能超过128个字符,必填;

是否启用签名:当启动时必须配置 认证方式 和 密钥;

认证方式:可选 密钥(使用网关内置鉴权方式验证)|自定义认证插件(使用自定义的鉴权逻辑),更多信息请查看Fizz网关的介绍;启用签名时必填;

密钥:第三方应用使用的密钥,可通过 生成随机密钥 按钮生成一个随机的密钥,启用签名时必填;

是否启用IP白名单:当启用时可以配置 IP白名单,网关会根据请求来源IP地址进行过滤;

IP白名单:IP段支持 1.2.3.100-120 和 1.2.3.*两种格式,仅最后一段可用范围或星号表示;

自定义配置:AppID级别的自定义配置供自定义插件使用,所有插件均可获取到此配置信息。

# 编辑appID

点击 编辑 按钮弹出编辑窗口,如图所示。

manager_app_id_edit_1

manager_app_id_edit_2

# 删除appID

点击 删除 按钮弹出删除确认窗口,如图所示。

manager_app_id_delete_1

manager_app_id_delete_2

点击 确定 按钮后删除appID,如果appID存在关联的路由配置时,对应关联的路由配置也会一起删除。

上次更新: 2020-11-9 11:50
- + diff --git a/docs/guide/manager/manager_gateway_aggregate_cache.html b/docs/guide/manager/manager_gateway_aggregate_cache.html index 3c95485..81e5c0d 100644 --- a/docs/guide/manager/manager_gateway_aggregate_cache.html +++ b/docs/guide/manager/manager_gateway_aggregate_cache.html @@ -7,7 +7,7 @@ - + @@ -23,7 +23,7 @@ 使用文档 查看源码 -

# 概述

网关缓存功能用于查询Fizz网关实例本地缓存的已发布接口信息,可以快速的了解当前网关实例生效的全部接口,同时通过查看后台接口发布版本号与网关实例本地缓存的接口版本号是否一致可以排查接口缓存问题,下面介绍网关缓存功能的操作。

# 网关列表

菜单位置:服务编排 > 网关缓存。点击菜单后进入网关列表页面,如图所示。

manager_aggregate_gateway_list_query

Fizz网关与后台注册到同一个eureka注册中心,后台通过eureka获取网关的实例列表。

# 网关缓存列表

点击 查看 按钮后弹出网关详情页面,该页面显示所选网关实例的接口缓存列表,如图所示。

manager_aggregate_gateway_cache_list_query_1

manager_aggregate_gateway_cache_list_query_2

# 网关缓存详情

点击 查看 按钮弹出所选接口的配置详情,如图所示。

manager_aggregate_gateway_cache_detail_1

manager_aggregate_gateway_cache_detail_2

上次更新: 2020-11-9 11:50
- + diff --git a/docs/guide/manager/manager_gateway_group.html b/docs/guide/manager/manager_gateway_group.html index 0e2bfa4..019efcf 100644 --- a/docs/guide/manager/manager_gateway_group.html +++ b/docs/guide/manager/manager_gateway_group.html @@ -7,7 +7,7 @@ - + @@ -23,7 +23,7 @@ 使用文档 查看源码 -

# 概述

网关分组功能用于维护分组元数据,将网关实例IP与分组关联,通过为不同的分组配置不同的路由策略,从而实现网关的分组管理。

# 分组示例

我们的线上业务涉及To C(个人用户)、To B(企业)、To T(第三方),对于不同业务会有对应的机器接受请求访问,不同的业务需要有各自的路由策略,因此进行了如下的分组划分。

分组ID 分组名称 描述
default 默认分组 默认分组是后台默认创建的分组,不用指定IP,不属于其它分组的机器都归到默认分组,默认分组不可修改或删除
c 2c分组 只接受面向个人用户的请求
b 2b分组 只接受面向企业的请求
t 面向第三方的分组 只接受面向第三方的请求

下面介绍网关分组功能的操作。

# 分组列表

菜单位置:网关管理 > 网关分组。点击菜单后进入分组列表页面,如图所示。

manager_gateway_group_list_query

# 新增分组

点击 新增 按钮弹出新增窗口,如图所示。

manager_gateway_group_add_1

manager_gateway_group_add_2

分组ID:分组的唯一标识,长度不能超过32个字符,必填;

分组名称:分组的名称,用于在分组选项时展示,长度不能超过32个字符,必填;

网关实例IP:Fizz网关集群内的机器IP地址,多个IP地址使用逗号分隔。

# 编辑分组

点击 编辑 按钮弹出编辑窗口,如图所示。

manager_gateway_group_edit_1

manager_gateway_group_edit_2

# 删除分组

点击 删除 按钮弹出删除确认窗口,如图所示。

manager_gateway_group_delete_1

manager_gateway_group_delete_2

点击 确定 按钮后删除网关分组,如果网关分组存在关联的路由配置时,需要将关联的路由配置全部删除后才能删除分组。

上次更新: 2020-11-9 11:50
- + diff --git a/docs/guide/manager/manager_overview.html b/docs/guide/manager/manager_overview.html index defb2f7..4e42828 100644 --- a/docs/guide/manager/manager_overview.html +++ b/docs/guide/manager/manager_overview.html @@ -7,7 +7,7 @@ - + @@ -23,7 +23,7 @@ 使用文档 查看源码 -

# 概述

Fizz管理后台是Fizz网关的配套系统,基于Java、Vue开发,通过界面对Fizz网关集群进行各项配置。

# 功能

Fizz管理后台包含如下功能:

- + diff --git a/docs/guide/manager/manager_plugin.html b/docs/guide/manager/manager_plugin.html index c581e2d..f3a9537 100644 --- a/docs/guide/manager/manager_plugin.html +++ b/docs/guide/manager/manager_plugin.html @@ -7,7 +7,7 @@ - + @@ -23,7 +23,7 @@ 使用文档 查看源码 -

# 概述

插件管理功能用于维护插件元数据,定义路由级别的自定义属性、插件级别的自定义配置信息。创建的插件用于路由管理设置时启用,当网关接受请求匹配路由规则时会触发启用的插件逻辑执行,插件逻辑中可获取到自定义的属性数据。

# 插件列表

菜单位置:网关管理 > 插件管理。点击菜单后进入插件管理列表页面,如图所示。

manager_plugin_list_query

# 新增插件

点击 新增 按钮弹出新增窗口,如图所示。

manager_plugin_add_1

manager_plugin_add_2

插件名称:插件名称由英文字母、下划线或数字组成,不能以数字开头,长度不能超过50个字符,必填;

插件描述:插件的简要描述,长度不能超过50个字符,必填;

默认执行顺序:插件的默认执行顺序,按从小到大排序,值越小越先执行,取值范围0~255,必填;

表单定义:路由级别的自定义属性,在路由管理配置启用插件时前端会将表单定义转化为表单输入界面,更多信息请查看路由管理介绍。表单规范说明如下:

/*
+        

# 概述

插件管理功能用于维护插件元数据,定义路由级别的自定义属性、插件级别的自定义配置信息。创建的插件用于路由管理设置时启用,当网关接受请求匹配路由规则时会触发启用的插件逻辑执行,插件逻辑中可获取到自定义的属性数据。

# 插件列表

菜单位置:网关管理 > 插件管理。点击菜单后进入插件管理列表页面,如图所示。

manager_plugin_list_query

# 新增插件

点击 新增 按钮弹出新增窗口,如图所示。

manager_plugin_add_1

manager_plugin_add_2

插件名称:插件名称由英文字母、下划线或数字组成,不能以数字开头,长度不能超过50个字符,必填;

插件描述:插件的简要描述,长度不能超过50个字符,必填;

默认执行顺序:插件的默认执行顺序,按从小到大排序,值越小越先执行,取值范围0~255,必填;

表单定义:路由级别的自定义属性,在路由管理配置启用插件时前端会将表单定义转化为表单输入界面,更多信息请查看路由管理介绍。表单规范说明如下:

/*
 * plugin_config_design
 * 动态插件参考结构
 * */
@@ -143,6 +143,6 @@
       
       →
     

- + diff --git a/docs/guide/manager/manager_role.html b/docs/guide/manager/manager_role.html index 8077cd7..c5c08dc 100644 --- a/docs/guide/manager/manager_role.html +++ b/docs/guide/manager/manager_role.html @@ -7,7 +7,7 @@ - + @@ -23,7 +23,7 @@ 使用文档 查看源码 -

# 概述

角色管理功能维护角色元数据,通过配置角色拥有的菜单资源,限制用户只能操作拥有的角色对应的菜单资源,下面介绍角色管理功能的操作。

# 角色列表

菜单位置:权限管理 > 角色管理。点击菜单后进入角色列表页面,如图所示。

manager_role_list_query

# 添加角色

点击 新增 按钮弹出新增窗口,如图所示。

manager_role_add_1

manager_role_add_2

# 权限设置

勾选需要分配权限的角色,点击 权限设置 按钮弹出角色权限配置窗口,如图所示。

manager_role_auth_1

manager_role_auth_2

勾选菜单后点击 确定 按钮确认给角色分配菜单权限。

# 编辑角色

点击 编辑 按钮弹出编辑窗口,如图所示。

manager_role_edit_1

manager_role_edit_2

# 删除角色

点击 删除 按钮弹出删除确认窗口,如图所示。

manager_role_delete_1

manager_role_delete_2

点击 确定 按钮后删除角色。

上次更新: 2020-11-9 11:50
- + diff --git a/docs/guide/manager/manager_service.html b/docs/guide/manager/manager_service.html index 479424a..4d46ce9 100644 --- a/docs/guide/manager/manager_service.html +++ b/docs/guide/manager/manager_service.html @@ -7,7 +7,7 @@ - + @@ -23,7 +23,7 @@ 使用文档 查看源码 -

# 概述

服务管理功能维护服务元数据。服务编排中的服务是一个逻辑上的概念,用于对聚合接口的归类以及权限的分配。Fizz网关聚合接口的请求路径格式为 http://{ip}:{port}/proxy/{service}{apiPath},服务对应{service}段。

# 服务列表

菜单位置:服务编排 > 服务管理。点击菜单后进入服务列表页面,如图所示。

manager_service_list_query

# 新增服务

点击 新增 按钮弹出新增窗口,如图所示。

manager_service_add_1

manager_service_add_2

服务 ID:服务唯一标识,对应Fizz网关聚合接口请求路径(格式为 http://{ip}:{port}/proxy/{service}{apiPath})的{service}段,长度不能超过200个字符,必填;

服务名:服务名称,用于展示或者选项使用,必填;

团队:团队名称,长度不能超过200个字符;

负责人:负责人名称,长度不能超过200个字符;

描述:服务描述,长度不能超过2000个字符。

# 编辑服务

点击 编辑 按钮弹出编辑窗口,如图所示。

manager_service_edit_1

manager_service_edit_2

# 删除服务

点击 删除 按钮弹出删除确认窗口,如图所示。

manager_service_delete_1

manager_service_delete_2

点击 确定 按钮后删除服务,如果服务存在关联的聚合接口时,需要将关联的聚合接口全部删除后才能删除服务。

# 服务权限分配

点击 权限 按钮弹出权限配置窗口,如图所示。

manager_service_auth_1

manager_service_auth_2

服务创建人自动获得服务权限,服务权限可分配,拥有权限的用户才能操作对应的接口列表。

上次更新: 2020-11-9 11:50
- + diff --git a/docs/guide/manager/manager_source_statistics.html b/docs/guide/manager/manager_source_statistics.html index 346c9d4..cf3f669 100644 --- a/docs/guide/manager/manager_source_statistics.html +++ b/docs/guide/manager/manager_source_statistics.html @@ -7,7 +7,7 @@ - + @@ -23,7 +23,7 @@ 使用文档 查看源码 -

# 概述

Fizz网关会将访问请求数据(IP地址、网关分组、服务、应用、请求方法、API Path、请求时间)推送到Kafka中,管理后台消费Kafka消息统计接口访问数据。

接口统计功能以图表的形式展示指定时间段内每日的接口总数、访问次数,可查看接口的历史访问总次数以及最近请求时间。

# 接口访问统计

菜单位置:网关管理 > 接口统计。点击菜单后进入接口统计页面,如图所示。

manager_source_statistics_1.png

今天接口总数:从0时到当前时刻被调用不同接口的总数;

今天访问次数:从0时到当前时刻访问请求的总次数。

接口总数图表:显示指定时间段内每日被调用不同接口的总数曲线;

访问次数图表:显示指定时间段内每日访问请求的总次数曲线。

# 请求统计

接口统计界面下部为请求统计列表,如图所示。

manager_source_statistics_2.png

来源IP:网关请求的实际入口IP地址;

请求次数:( 唯一[来源IP、网关分组、服务名、请求方法、appID、API Path])历史总请求次数;

最近请求时间:( 唯一[来源IP、网关分组、服务名、请求方法、appID、API Path])最近一次调用时间。

上次更新: 2020-11-9 11:50
- +

# 概述

Fizz网关会将访问请求数据(IP地址、网关分组、服务、应用、请求方法、API Path、请求时间)推送到Kafka中,管理后台消费Kafka消息统计接口访问数据。

接口统计功能以图表的形式展示指定时间段内每日的接口总数、访问次数,可查看接口的历史访问总次数以及最近请求时间。

# 接口访问统计

菜单位置:网关管理 > 接口统计。点击菜单后进入接口统计页面,如图所示。

manager_source_statistics_1.png

今天接口总数:从0时到当前时刻被调用不同接口的总数;

今天访问次数:从0时到当前时刻访问请求的总次数。

接口总数图表:显示指定时间段内每日被调用不同接口的总数曲线;

访问次数图表:显示指定时间段内每日访问请求的总次数曲线。

# 请求统计

接口统计界面下部为请求统计列表,如图所示。

manager_source_statistics_2.png

来源IP:网关请求的实际入口IP地址;

请求次数:( 唯一[来源IP、网关分组、服务名、请求方法、appID、API Path])历史总请求次数;

最近请求时间:( 唯一[来源IP、网关分组、服务名、请求方法、appID、API Path])最近一次调用时间。

上次更新: 2020-11-9 11:50
+ diff --git a/docs/guide/manager/manager_user.html b/docs/guide/manager/manager_user.html index a2232a9..d83a3b0 100644 --- a/docs/guide/manager/manager_user.html +++ b/docs/guide/manager/manager_user.html @@ -7,7 +7,7 @@ - + @@ -23,11 +23,11 @@ 使用文档 查看源码 -

# 概述

用户管理功能用于维护用户元数据,包括用户信息维护、密码维护、角色配置。

# 用户列表

菜单位置:系统管理 > 用户管理。点击菜单后进入用户列表页面,如图所示。

manager_user_list_query

# 添加用户

点击 新增 按钮弹出新增窗口,如图所示。

manager_user_add_1

manager_user_add_2

电子邮箱:用户用于接收电子邮件的邮箱地址,后台涉及邮件发送业务使用该字段设置的邮箱地址来进行邮箱发送。

# 重置密码

勾选用户后点击 密码重置 按钮可为用户重置密码。

manager_user_reset_password_1

manager_user_reset_password_2

重置后的默认密码为AsdF1234!

# 编辑用户

点击 编辑 按钮弹出编辑窗口,如图所示。

manager_user_edit_1

manager_user_edit_2

# 删除用户

点击 删除 按钮弹出删除确认窗口,如图所示。

manager_user_delete_1

manager_user_delete_2

上次更新: 2020-11-9 11:50
- + diff --git a/docs/guide/plugin/index.html b/docs/guide/plugin/index.html index 9e7daa5..002d9ca 100644 --- a/docs/guide/plugin/index.html +++ b/docs/guide/plugin/index.html @@ -7,7 +7,7 @@ - + @@ -23,7 +23,7 @@ 使用文档 查看源码 -

# 概述

当需要在gateway中加入自定义的逻辑时,可通过fizz的插件机制实现,插件:
+

# 概述

当需要在gateway中加入自定义的逻辑时,可通过fizz的插件机制实现,插件:
1、类似spring的WebFilter,是fizz内部的WebFilter,由fizz调度;
2、对不同的请求,可配置不同的上下文参数,可通过manager完成配置;
3、若有多个插件,当前插件可获取前面插件的执行结果。

插件的开发和应用,分gateway开发、manager配置两部分,下面以一个例子,依次介绍。

# gateway开发

    实现
@@ -120,6 +120,6 @@
       
       →
     

- + diff --git a/docs/guide/proxy/index.html b/docs/guide/proxy/index.html index 0221ec3..1da1112 100644 --- a/docs/guide/proxy/index.html +++ b/docs/guide/proxy/index.html @@ -7,7 +7,7 @@ - + @@ -23,7 +23,7 @@ 使用文档 查看源码 -

# 路由转发介绍

路由转发也叫反向代理,为内部微服务提供统一的对外入口。支持以下功能:

  • 支持服务注册与发现
  • 支持负载均衡
  • 支持黑白名单机制
  • 支持配置插件

# 接入路由转发

  • 前提条件:接入Eureka注册中心
  • 开通白名单,接入注册中心的服务默认不对公网开放 (白名单在配置文件里配置serviceWhiteList)
  • 配置访问权限 (管理后台-接口代理-API查询)
上次更新: 2020-9-8 15:3
- + diff --git a/docs/index.html b/docs/index.html index 4b8fd6b..173a2d3 100644 --- a/docs/index.html +++ b/docs/index.html @@ -7,7 +7,7 @@ - + @@ -32,6 +32,6 @@

智能路由

支持服务注册与发现,支持负载均衡,支持配置插件和黑白名单。

服务编排

基于现有的业务微服务通过在线配置的方式快速的生成一个聚合接口。减少中间层胶水代码以及降低编码投入

插件机制

强大的插件系统,内置通用常用插件,同时支持自定义插件开发。

- + diff --git a/src/main/java/we/constants/CommonConstants.java b/src/main/java/we/constants/CommonConstants.java index e5bac3c..3174154 100644 --- a/src/main/java/we/constants/CommonConstants.java +++ b/src/main/java/we/constants/CommonConstants.java @@ -39,6 +39,15 @@ public class CommonConstants { public static final String WILDCARD_STAR = "*"; + /** + * Stop the underlying processes and response immediately, using in scripts + */ public static final String STOP_AND_RESPONSE_KEY = "_stopAndResponse"; + + /** + * Stop the underlying processes and redirect to the specified URL immediately, work with STOP_AND_RESPONSE_KEY using in scripts + */ + public static final String REDIRECT_URL_KEY = "_redirectUrl"; + } diff --git a/src/main/java/we/exception/RedirectException.java b/src/main/java/we/exception/RedirectException.java new file mode 100644 index 0000000..cd52dab --- /dev/null +++ b/src/main/java/we/exception/RedirectException.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2020 the original author or authors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package we.exception; + +/** + * @author Francis + */ +public class RedirectException extends RuntimeException { + + private String redirectUrl; + + public RedirectException(String message, String redirectUrl) { + super(message); + this.redirectUrl = redirectUrl; + } + + /** + * + */ + private static final long serialVersionUID = 1L; + + public String getRedirectUrl() { + return redirectUrl; + } + + public void setRedirectUrl(String redirectUrl) { + this.redirectUrl = redirectUrl; + } + +} diff --git a/src/main/java/we/exception/StopAndResponseException.java b/src/main/java/we/exception/StopAndResponseException.java index fc7c182..16cf94d 100644 --- a/src/main/java/we/exception/StopAndResponseException.java +++ b/src/main/java/we/exception/StopAndResponseException.java @@ -18,7 +18,7 @@ package we.exception; /** - * @author unknown + * @author Francis */ public class StopAndResponseException extends RuntimeException { diff --git a/src/main/java/we/filter/FilterExceptionHandlerConfig.java b/src/main/java/we/filter/FilterExceptionHandlerConfig.java index b17bb1c..30b77aa 100644 --- a/src/main/java/we/filter/FilterExceptionHandlerConfig.java +++ b/src/main/java/we/filter/FilterExceptionHandlerConfig.java @@ -17,6 +17,8 @@ package we.filter; +import java.net.URI; + import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.annotation.Order; @@ -27,6 +29,7 @@ import org.springframework.http.server.reactive.ServerHttpResponse; import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.WebExceptionHandler; import reactor.core.publisher.Mono; +import we.exception.RedirectException; import we.exception.StopAndResponseException; import we.util.WebUtils; @@ -41,13 +44,22 @@ public class FilterExceptionHandlerConfig { private static final String filterExceptionHandler = "filterExceptionHandler"; @Override public Mono handle(ServerWebExchange exchange, Throwable t) { - if (t instanceof StopAndResponseException) { + if (t instanceof StopAndResponseException) { StopAndResponseException ex = (StopAndResponseException) t; if (ex.getData() != null) { ServerHttpResponse resp = exchange.getResponse(); resp.getHeaders().add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE); return resp.writeWith(Mono.just(resp.bufferFactory().wrap(ex.getData().toString().getBytes()))); } + } + if (t instanceof RedirectException) { + RedirectException ex = (RedirectException) t; + if (ex.getRedirectUrl() != null) { + ServerHttpResponse resp = exchange.getResponse(); + resp.setStatusCode(HttpStatus.MOVED_PERMANENTLY); + resp.getHeaders().setLocation(URI.create(ex.getRedirectUrl())); + return Mono.empty(); + } } Mono vm = WebUtils.responseError(exchange, filterExceptionHandler, HttpStatus.INTERNAL_SERVER_ERROR.value(), t.getMessage(), t); return vm; diff --git a/src/main/java/we/fizz/input/ScriptHelper.java b/src/main/java/we/fizz/input/ScriptHelper.java index eee3aa8..bd8ca9a 100644 --- a/src/main/java/we/fizz/input/ScriptHelper.java +++ b/src/main/java/we/fizz/input/ScriptHelper.java @@ -32,6 +32,7 @@ import com.alibaba.fastjson.JSON; import org.springframework.util.StringUtils; import we.constants.CommonConstants; +import we.exception.RedirectException; import we.exception.StopAndResponseException; import we.fizz.StepContext; import we.util.Script; @@ -136,10 +137,18 @@ public class ScriptHelper { && rs.get(CommonConstants.STOP_AND_RESPONSE_KEY) instanceof Boolean && (Boolean) rs.get(CommonConstants.STOP_AND_RESPONSE_KEY)) { rs.remove(CommonConstants.STOP_AND_RESPONSE_KEY); + + // redirect + if(rs.get(CommonConstants.REDIRECT_URL_KEY) != null) { + throw new RedirectException("stop and redirect", String.valueOf(rs.get(CommonConstants.REDIRECT_URL_KEY))); + } + // 测试模式返回StepContext if (stepContext.returnContext()) { rs.put("_context", stepContext); } + + // exception throw new StopAndResponseException("stop and response", JSON.toJSONString(rs)); } else { rs.remove(CommonConstants.STOP_AND_RESPONSE_KEY); From 70c132059b9efb22b571a9aed5b77dc6deece39d Mon Sep 17 00:00:00 2001 From: Francis Dong Date: Thu, 19 Nov 2020 16:52:34 +0800 Subject: [PATCH 08/14] #15 return exception information while failed to execute script --- js/context.js | 6 ++ .../we/exception/ExecuteScriptException.java | 67 +++++++++++++++++++ .../filter/FilterExceptionHandlerConfig.java | 18 +++++ .../java/we/filter/FizzGatewayFilter.java | 2 +- src/main/java/we/fizz/AggregateResult.java | 12 +++- src/main/java/we/fizz/Pipeline.java | 18 ++--- src/main/java/we/fizz/StepContext.java | 30 +++++++++ src/main/java/we/fizz/input/RequestInput.java | 14 ++-- src/main/java/we/fizz/input/ScriptHelper.java | 8 ++- src/main/java/we/legacy/RespEntity.java | 9 +++ src/main/java/we/util/WebUtils.java | 5 ++ 11 files changed, 170 insertions(+), 19 deletions(-) create mode 100644 src/main/java/we/exception/ExecuteScriptException.java diff --git a/js/context.js b/js/context.js index 7e278e0..0a31511 100644 --- a/js/context.js +++ b/js/context.js @@ -8,6 +8,12 @@ var context = { elapsedTimes: [{ [actionName]: 123, // 操作名称:耗时 }], + + // exception info + exceptionMessage: "", + exceptionStacks: "", + exceptionData: "", // such as script source code that cause exception + // 客户输入和接口的返回结果 input: { diff --git a/src/main/java/we/exception/ExecuteScriptException.java b/src/main/java/we/exception/ExecuteScriptException.java new file mode 100644 index 0000000..98bffd9 --- /dev/null +++ b/src/main/java/we/exception/ExecuteScriptException.java @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2020 the original author or authors. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package we.exception; + +import we.fizz.StepContext; + +/** + * @author Francis + */ +public class ExecuteScriptException extends RuntimeException { + + private StepContext stepContext; + + private Object data; + + public ExecuteScriptException(String message, StepContext stepContext, Object data) { + super(message); + this.data = data; + this.stepContext = stepContext; + this.stepContext.setExceptionInfo(this, data); + } + + public ExecuteScriptException(Throwable cause, StepContext stepContext, Object data) { + super("execute script failed: " + cause.getMessage(), cause); + this.data = data; + this.stepContext = stepContext; + this.setStackTrace(cause.getStackTrace()); + this.stepContext.setExceptionInfo(this, data); + } + + /** + * + */ + private static final long serialVersionUID = 1L; + + public Object getData() { + return data; + } + + public void setData(Object data) { + this.data = data; + } + + public StepContext getStepContext() { + return stepContext; + } + + public void setStepContext(StepContext stepContext) { + this.stepContext = stepContext; + } + +} diff --git a/src/main/java/we/filter/FilterExceptionHandlerConfig.java b/src/main/java/we/filter/FilterExceptionHandlerConfig.java index 30b77aa..ac8eea1 100644 --- a/src/main/java/we/filter/FilterExceptionHandlerConfig.java +++ b/src/main/java/we/filter/FilterExceptionHandlerConfig.java @@ -29,8 +29,11 @@ import org.springframework.http.server.reactive.ServerHttpResponse; import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.WebExceptionHandler; import reactor.core.publisher.Mono; +import we.exception.ExecuteScriptException; import we.exception.RedirectException; import we.exception.StopAndResponseException; +import we.legacy.RespEntity; +import we.util.JacksonUtils; import we.util.WebUtils; /** @@ -60,6 +63,21 @@ public class FilterExceptionHandlerConfig { resp.getHeaders().setLocation(URI.create(ex.getRedirectUrl())); return Mono.empty(); } + } + if (t instanceof ExecuteScriptException) { + ExecuteScriptException ex = (ExecuteScriptException) t; + ServerHttpResponse resp = exchange.getResponse(); + resp.getHeaders().add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE); + + RespEntity rs = null; + String reqId = exchange.getRequest().getId(); + if (ex.getStepContext() != null && ex.getStepContext().returnContext()) { + rs = new RespEntity(HttpStatus.INTERNAL_SERVER_ERROR.value(), t.getMessage(), reqId, ex.getStepContext()); + return resp.writeWith(Mono.just(resp.bufferFactory().wrap(JacksonUtils.writeValueAsString(rs).getBytes()))); + }else { + rs = new RespEntity(HttpStatus.INTERNAL_SERVER_ERROR.value(), t.getMessage(), reqId); + return resp.writeWith(Mono.just(resp.bufferFactory().wrap(rs.toString().getBytes()))); + } } Mono vm = WebUtils.responseError(exchange, filterExceptionHandler, HttpStatus.INTERNAL_SERVER_ERROR.value(), t.getMessage(), t); return vm; diff --git a/src/main/java/we/filter/FizzGatewayFilter.java b/src/main/java/we/filter/FizzGatewayFilter.java index 7c4860f..d6c4fc4 100644 --- a/src/main/java/we/filter/FizzGatewayFilter.java +++ b/src/main/java/we/filter/FizzGatewayFilter.java @@ -74,7 +74,7 @@ public class FizzGatewayFilter implements WebFilter { ServerHttpRequest request = exchange.getRequest(); ServerHttpResponse serverHttpResponse = exchange.getResponse(); - String path = WebUtils.PATH_PREFIX + WebUtils.getServiceId(exchange) + WebUtils.getReqPath(exchange); + String path = WebUtils.getPathPrefix(exchange) + WebUtils.getServiceId(exchange) + WebUtils.getReqPath(exchange); String method = request.getMethodValue(); AggregateResource aggregateResource = configLoader.matchAggregateResource(method, path); if (aggregateResource == null) { diff --git a/src/main/java/we/fizz/AggregateResult.java b/src/main/java/we/fizz/AggregateResult.java index 3f8abaa..72e4f50 100644 --- a/src/main/java/we/fizz/AggregateResult.java +++ b/src/main/java/we/fizz/AggregateResult.java @@ -29,9 +29,11 @@ import org.springframework.util.MultiValueMap; public class AggregateResult { private MultiValueMap headers; - + private Map body; + private StepContext stepContext; + public MultiValueMap getHeaders() { return headers; } @@ -48,4 +50,12 @@ public class AggregateResult { this.body = body; } + public StepContext getStepContext() { + return stepContext; + } + + public void setStepContext(StepContext stepContext) { + this.stepContext = stepContext; + } + } diff --git a/src/main/java/we/fizz/Pipeline.java b/src/main/java/we/fizz/Pipeline.java index 87baf7c..3fa6564 100644 --- a/src/main/java/we/fizz/Pipeline.java +++ b/src/main/java/we/fizz/Pipeline.java @@ -36,12 +36,14 @@ import com.alibaba.fastjson.JSON; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; +import we.exception.ExecuteScriptException; import we.fizz.input.ClientInputConfig; import we.fizz.input.Input; import we.fizz.input.InputConfig; import we.fizz.input.PathMapping; import we.fizz.input.ScriptHelper; import we.flume.clients.log4j2appender.LogService; +import we.util.JacksonUtils; import we.util.JsonSchemaUtils; import we.util.MapUtil; @@ -55,7 +57,7 @@ import we.util.MapUtil; public class Pipeline { private static final Logger LOGGER = LoggerFactory.getLogger(Pipeline.class); private LinkedList steps = new LinkedList(); - private StepContext stepContext= new StepContext<>(); + private StepContext stepContext = new StepContext<>(); public void addStep(Step step) { steps.add(step); } @@ -184,8 +186,8 @@ public class Pipeline { stepResponse.setResult(stepBody); } } catch (ScriptException e) { - LOGGER.warn("execute script failed, {}", e); - throw new RuntimeException("execute script failed"); + LOGGER.warn("execute script failed, {}", JacksonUtils.writeValueAsString(scriptCfg), e); + throw new ExecuteScriptException(e, stepContext, scriptCfg); } } } @@ -238,8 +240,8 @@ public class Pipeline { body.putAll((Map) respBody); } } catch (ScriptException e) { - LOGGER.warn("execute script failed, {}", e); - throw new RuntimeException("execute script failed"); + LOGGER.warn("execute script failed, {}", JacksonUtils.writeValueAsString(scriptCfg), e); + throw new ExecuteScriptException(e, stepContext, scriptCfg); } } response.put("body", body); @@ -249,7 +251,7 @@ public class Pipeline { Map respBody = (Map) response.get("body"); // 测试模式返回StepContext if(stepContext.returnContext()) { - respBody.put("_context", stepContext); + respBody.put(stepContext.CONTEXT_FIELD, stepContext); } aggResult.setBody((Map) response.get("body")); @@ -302,8 +304,8 @@ public class Pipeline { return errorList; } } catch (ScriptException e) { - LOGGER.warn("execute script failed", e); - throw new RuntimeException("execute script failed"); + LOGGER.warn("execute script failed, {}", JacksonUtils.writeValueAsString(scriptValidate), e); + throw new ExecuteScriptException(e, stepContext, scriptValidate); } } } diff --git a/src/main/java/we/fizz/StepContext.java b/src/main/java/we/fizz/StepContext.java index 342ad0c..dd8d296 100644 --- a/src/main/java/we/fizz/StepContext.java +++ b/src/main/java/we/fizz/StepContext.java @@ -39,6 +39,13 @@ public class StepContext extends ConcurrentHashMap { public static final String ELAPSED_TIMES = "elapsedTimes"; public static final String DEBUG = "debug"; public static final String RETURN_CONTEXT = "returnContext"; + // context field in response body + public static final String CONTEXT_FIELD = "_context"; + + // exception info + public static final String EXCEPTION_MESSAGE = "exceptionMessage"; + public static final String EXCEPTION_STACKS = "exceptionStacks"; + public static final String EXCEPTION_DATA = "exceptionData"; public void setDebug(Boolean debug) { this.put((K)DEBUG, (V)debug); @@ -68,6 +75,29 @@ public class StepContext extends ConcurrentHashMap { return Boolean.valueOf((String)getInputReqHeader(RETURN_CONTEXT)); } + /** + * set exception information + * @param cause exception + * @param exceptionData data that cause the exception, such as script source code, etc. + */ + public void setExceptionInfo(Throwable cause, Object exceptionData) { + this.put((K) EXCEPTION_MESSAGE, (V) cause.getMessage()); + this.put((K) EXCEPTION_DATA, (V) exceptionData); + + StackTraceElement[] stacks = cause.getStackTrace(); + if (stacks != null && stacks.length > 0) { + String[] arr = new String[stacks.length]; + for (int i = 0; i < stacks.length; i++) { + StackTraceElement ste = stacks[i]; + StringBuffer sb = new StringBuffer(); + sb.append(ste.getClassName()).append(".").append(ste.getMethodName()).append("(") + .append(ste.getFileName()).append(":").append(ste.getLineNumber()).append(")"); + arr[i] = sb.toString(); + } + this.put((K) EXCEPTION_STACKS, (V) arr); + } + } + public synchronized void addElapsedTime(String actionName, Long milliSeconds) { List> elapsedTimes = (List>) this.get(ELAPSED_TIMES); if (elapsedTimes == null) { diff --git a/src/main/java/we/fizz/input/RequestInput.java b/src/main/java/we/fizz/input/RequestInput.java index 0494390..bb1ea25 100644 --- a/src/main/java/we/fizz/input/RequestInput.java +++ b/src/main/java/we/fizz/input/RequestInput.java @@ -38,10 +38,12 @@ import com.alibaba.fastjson.JSON; import reactor.core.publisher.Mono; import we.FizzAppContext; import we.constants.CommonConstants; +import we.exception.ExecuteScriptException; import we.fizz.StepContext; import we.fizz.StepResponse; import we.flume.clients.log4j2appender.LogService; import we.proxy.FizzWebClient; +import we.util.JacksonUtils; import we.util.MapUtil; /** @@ -131,8 +133,8 @@ public class RequestInput extends Input { } } catch (ScriptException e) { LogService.setBizId(inputContext.getStepContext().getTraceId()); - LOGGER.warn("execute script failed, {}", e); - throw new RuntimeException("execute script failed"); + LOGGER.warn("execute script failed, {}", JacksonUtils.writeValueAsString(scriptCfg), e); + throw new ExecuteScriptException(e, stepContext, scriptCfg); } } request.put("body", body); @@ -187,8 +189,8 @@ public class RequestInput extends Input { } } catch (ScriptException e) { LogService.setBizId(inputContext.getStepContext().getTraceId()); - LOGGER.warn("execute script failed, {}", e); - throw new RuntimeException("execute script failed"); + LOGGER.warn("execute script failed, {}", JacksonUtils.writeValueAsString(scriptCfg), e); + throw new ExecuteScriptException(e, stepContext, scriptCfg); } } response.put("body", body); @@ -247,8 +249,8 @@ public class RequestInput extends Input { return needRun != null ? needRun : Boolean.TRUE; } catch (ScriptException e) { LogService.setBizId(inputContext.getStepContext().getTraceId()); - LOGGER.warn("execute script failed", e); - throw new RuntimeException("execute script failed"); + LOGGER.warn("execute script failed, {}", JacksonUtils.writeValueAsString(condition), e); + throw new ExecuteScriptException(e, stepContext, condition); } } diff --git a/src/main/java/we/fizz/input/ScriptHelper.java b/src/main/java/we/fizz/input/ScriptHelper.java index bd8ca9a..545ae46 100644 --- a/src/main/java/we/fizz/input/ScriptHelper.java +++ b/src/main/java/we/fizz/input/ScriptHelper.java @@ -32,9 +32,11 @@ import com.alibaba.fastjson.JSON; import org.springframework.util.StringUtils; import we.constants.CommonConstants; +import we.exception.ExecuteScriptException; import we.exception.RedirectException; import we.exception.StopAndResponseException; import we.fizz.StepContext; +import we.util.JacksonUtils; import we.util.Script; import we.util.ScriptUtils; @@ -118,8 +120,8 @@ public class ScriptHelper { PathMapping.setByPath(target, entry.getKey(), execute(scriptCfg, ctxNode, stepContext, clazz)); } } catch (ScriptException e) { - LOGGER.warn("execute script failed, {}", e); - throw new RuntimeException("execute script failed"); + LOGGER.warn("execute script failed, {}", JacksonUtils.writeValueAsString(scriptCfg), e); + throw new ExecuteScriptException(e, stepContext, scriptCfg); } } if(starEntryKey != null) { @@ -145,7 +147,7 @@ public class ScriptHelper { // 测试模式返回StepContext if (stepContext.returnContext()) { - rs.put("_context", stepContext); + rs.put(stepContext.CONTEXT_FIELD, stepContext); } // exception diff --git a/src/main/java/we/legacy/RespEntity.java b/src/main/java/we/legacy/RespEntity.java index 4a81034..a85d7af 100644 --- a/src/main/java/we/legacy/RespEntity.java +++ b/src/main/java/we/legacy/RespEntity.java @@ -37,12 +37,21 @@ public class RespEntity { public String message; public String reqId; + + public Object _context; public RespEntity(int code, String msg, @Nullable String reqId) { msgCode = code; message = msg; this.reqId = reqId; } + + public RespEntity(int code, String msg, @Nullable String reqId, Object stepContext) { + msgCode = code; + message = msg; + this.reqId = reqId; + this._context = stepContext; + } private static final String resb = "$resb"; diff --git a/src/main/java/we/util/WebUtils.java b/src/main/java/we/util/WebUtils.java index 43e43ea..775d10d 100644 --- a/src/main/java/we/util/WebUtils.java +++ b/src/main/java/we/util/WebUtils.java @@ -120,6 +120,11 @@ public abstract class WebUtils { } return svc; } + + public static String getPathPrefix(ServerWebExchange exchange) { + String p = exchange.getRequest().getPath().value(); + return p.substring(0, p.indexOf(getServiceId(exchange))); + } public static Mono getDirectResponse(ServerWebExchange exchange) { return (Mono) exchange.getAttributes().get(WebUtils.directResponse); From ca344082f6d261d30d5a13a6c661e1552ac4d1ee Mon Sep 17 00:00:00 2001 From: zhongjie Date: Fri, 20 Nov 2020 17:16:05 +0800 Subject: [PATCH 09/14] adapt the application.yml file for auto install --- src/main/java/we/FizzGatewayApplication.java | 2 +- src/main/resources/application.yml | 53 ++++++++++---------- 2 files changed, 27 insertions(+), 28 deletions(-) diff --git a/src/main/java/we/FizzGatewayApplication.java b/src/main/java/we/FizzGatewayApplication.java index 25d46ae..0229a3e 100644 --- a/src/main/java/we/FizzGatewayApplication.java +++ b/src/main/java/we/FizzGatewayApplication.java @@ -12,7 +12,7 @@ import org.springframework.cloud.client.discovery.EnableDiscoveryClient; exclude = {ErrorWebFluxAutoConfiguration.class, RedisAutoConfiguration.class, RedisReactiveAutoConfiguration.class}, scanBasePackages = {"we"} ) -@NacosPropertySource(dataId = "application", groupId = "fizz-gateway", autoRefreshed = true) +@NacosPropertySource(dataId = "${nacos.config.data-id}", groupId = "${nacos.config.group}", autoRefreshed = true) @EnableDiscoveryClient public class FizzGatewayApplication { diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 1b0c449..9ecca22 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -1,53 +1,53 @@ # if you do not use Apollo, ignore the follow config -######################### Apollo config start ##################################### +################################################## Apollo config start ################################################## apollo: # if use Apollo set this flag to true - enabled: false + enabled: false #use Apollo? (default:false) bootstrap: # if use Apollo set this flag to true - enabled: false - namespaces: application + enabled: false #use Apollo? + namespaces: application #please input the apollo bootstrap namespaces (default:application) eagerLoad: # if use Apollo set this flag to true - enabled: false -######################### Apollo config end ####################################### + enabled: false #use Apollo? +################################################### Apollo config end ################################################### # if you do not use Nacos, ignore the follow config -######################### Nacos config start ###################################### +################################################## Nacos config start ################################################### nacos: config: # if use Nacos config set this flag to true - enabled: false + enabled: false #use Nacos Config? (default:false) # need replace - server-addr: localhost:8848 + server-addr: localhost:8848 #please input the nacos config server-addr (default:localhost:8848) auto-refresh: true - group: fizz-gateway - data-id: application - type: PROPERTIES + group: fizz-gateway #please input the nacos config group (default:fizz-gateway) + data-id: application #please input the nacos config data-id (default:application) + type: PROPERTIES #please input the nacos config type (default:PROPERTIES) # need replace - namespace: c37ecd3b-e8b3-42cc-ba94-98e931e33683 + namespace: null #please input the nacos config type (default:null) discovery: # if use Nacos discovery set this flag to true - enabled: false + enabled: false #use Nacos Discovery? (default:false) # need replace - server-addr: localhost:8848 + server-addr: localhost:8848 #please input the nacos discovery server-addr (default:localhost:8848) auto-register: true register: - group-name: fizz-gateway -######################### Nacos config end ####################################### + group-name: fizz-gateway #please input the nacos discovery register group-name (default:fizz-gateway) +################################################### Nacos config end #################################################### # if you do not use Eureka, ignore the follow config -######################### Eureka config start #################################### +################################################## Eureka config start ################################################## eureka: client: # if use Eureka set this flag to true - enabled: false + enabled: false #use Eureka? (default:false) serviceUrl: # need replace - defaultZone: http://localhost:6600/eureka/ + defaultZone: http://localhost:6600/eureka/ #please input the eureka client serviceUrl defaultZone (default:http://localhost:6600/eureka/) instance: prefer-ip-address: true -######################### Eureka config end ###################################### +################################################### Eureka config end ################################################### server: port: 8600 @@ -64,13 +64,13 @@ spring: aggregate: redis: # need replace - host: localhost + host: localhost #please input the redis host (default:localhost) # need replace - port: 6379 + port: 6379 #please input the redis port (default:6379) # need replace - password: 123456 + password: 123456 #please input the redis password (default:123456) # need replace - database: 9 + database: 9 #please input the redis database (default:9) proxy-webclient: name: proxy aggr-webclient: @@ -78,5 +78,4 @@ aggr-webclient: fizz-web-client: timeout: 20000 log: - headers: COOKIE,FIZZ-APPID,FIZZ-SECRETKEY,FIZZ-SIGN,FIZZ-TS,FIZZ-RSV - + headers: COOKIE,FIZZ-APPID,FIZZ-SECRETKEY,FIZZ-SIGN,FIZZ-TS,FIZZ-RSV \ No newline at end of file From f89e4df27d3fcd2d9a66aec5a698adf38bffa77c Mon Sep 17 00:00:00 2001 From: Francis Dong Date: Tue, 24 Nov 2020 11:10:53 +0800 Subject: [PATCH 10/14] #19 add embedded default common.js in classpath --- src/main/java/we/util/ScriptUtils.java | 22 ++- src/main/resources/js/common.js | 230 +++++++++++++++++++++++++ 2 files changed, 250 insertions(+), 2 deletions(-) create mode 100644 src/main/resources/js/common.js diff --git a/src/main/java/we/util/ScriptUtils.java b/src/main/java/we/util/ScriptUtils.java index ba0c76a..08bd975 100644 --- a/src/main/java/we/util/ScriptUtils.java +++ b/src/main/java/we/util/ScriptUtils.java @@ -18,10 +18,16 @@ package we.util; import org.apache.commons.lang3.StringUtils; +import org.springframework.core.io.ClassPathResource; import javax.script.*; + +import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.URL; import java.util.HashMap; import java.util.Map; @@ -42,6 +48,8 @@ public abstract class ScriptUtils { private static final String clazz = "clazz"; private static final String resJsonStr = "resJsonStr"; + + private static final String COMMON_JS_PATH = "js/common.js"; public static Map recreateJavascriptEngineSignalMap = new HashMap<>(); @@ -51,10 +59,20 @@ public abstract class ScriptUtils { private static ScriptEngine createJavascriptEngine() throws ScriptException { ScriptEngine eng = engineManger.getEngineByName(JAVA_SCRIPT); - try { - eng.eval(new FileReader("js/common.js")); + try { + // custom common.js file + File f = new File(COMMON_JS_PATH); + if(f.exists()) { + eng.eval(new FileReader(COMMON_JS_PATH)); + return eng; + } + // use embedded common.js while there is not custom common.js file + ClassPathResource res = new ClassPathResource(COMMON_JS_PATH); + eng.eval(new InputStreamReader(res.getInputStream())); return eng; } catch (FileNotFoundException e) { + throw new ScriptException(e); + } catch (IOException e) { throw new ScriptException(e); } } diff --git a/src/main/resources/js/common.js b/src/main/resources/js/common.js new file mode 100644 index 0000000..689ff00 --- /dev/null +++ b/src/main/resources/js/common.js @@ -0,0 +1,230 @@ +/** + * context 上下文便捷操作函数 + * + */ +var common = { + /* *********** private function begin *********** */ + + // 获取上下文中客户端请求对象 + getInputReq: function (ctx){ + if(!ctx || !ctx['input'] || !ctx['input']['request']){ + return {}; + } + return ctx['input']['request'] + }, + + // 获取上下文步骤中请求接口的请求对象 + getStepReq: function (ctx, stepName, requestName){ + if(!ctx || !stepName || !requestName){ + return {}; + } + if(!ctx[stepName] || !ctx[stepName]['requests'] || !ctx[stepName]['requests'][requestName] || + !ctx[stepName]['requests'][requestName]['request']){ + return {}; + } + return ctx[stepName]['requests'][requestName]['request']; + }, + + // 获取上下文步骤中请求接口的响应对象 + getStepResp: function (ctx, stepName, requestName){ + if(!ctx || !stepName || !requestName){ + return {}; + } + if(!ctx[stepName] || !ctx[stepName]['requests'] || !ctx[stepName]['requests'][requestName] || + !ctx[stepName]['requests'][requestName]['response']){ + return {}; + } + return ctx[stepName]['requests'][requestName]['response']; + }, + + /* *********** private function end *********** */ + + /* *********** input begin ************ */ + + /** + * 获取客户端请求头 + * @param {*} ctx 上下文 【必填】 + * @param {*} headerName 请求头字段名 【选填】,不传时返回所有请求头 + */ + getInputReqHeader: function (ctx, headerName){ + var req = this.getInputReq(ctx); + var headers = req['headers'] || {}; + return headerName ? headers[headerName] : headers; + }, + + /** + * 获取客户端URL请求参数(query string) + * @param {*} ctx 上下文 【必填】 + * @param {*} paramName URL参数名 【选填】,不传时返回所有请求参数 + */ + getInputReqParam: function (ctx, paramName){ + var req = this.getInputReq(ctx); + var params = req['params'] || {}; + return paramName ? params[paramName] : params; + }, + + /** + * 获取客户端请求体 + * @param {*} ctx 上下文 【必填】 + * @param {*} field 字段名 【选填】,不传时返回整个请求体 + */ + getInputReqBody: function (ctx, field){ + var req = this.getInputReq(ctx); + var body = req['body'] || {}; + return field ? body[field] : body; + }, + + /** + * 获取返回给客户端的响应头 + * @param {*} ctx 上下文 【必填】 + * @param {*} headerName 响应头字段名 【选填】,不传时返回所有响应头 + */ + getInputRespHeader: function (ctx, headerName){ + var req = this.getInputReq(ctx); + var headers = req['headers'] || {}; + return headerName ? headers[headerName] : headers; + }, + + /** + * 获取返回给客户端的响应体 + * @param {*} ctx 上下文 【必填】 + * @param {*} field 字段名 【选填】,不传时返回整个响应体 + */ + getInputRespBody: function (ctx, field){ + var req = this.getInputReq(ctx); + var body = req['body'] || {}; + return field ? body[field] : body; + }, + + /* *********** input begin ************ */ + + /* *********** step request begin ************ */ + + /** + * 获取步骤中调用的接口的请求头 + * @param {*} ctx 上下文 【必填】 + * @param {*} stepName 步骤名【必填】 + * @param {*} requestName 请求的接口名 【必填】 + * @param {*} headerName 请求头字段名 【选填】,不传时返回所有请求头 + */ + getStepReqHeader: function (ctx, stepName, requestName, headerName){ + var req = this.getStepReq(ctx, stepName, requestName); + var headers = req['headers'] || {}; + return headerName ? headers[headerName] : headers; + }, + + /** + * 获取步骤中调用的接口的URL参数 + * @param {*} ctx 上下文 【必填】 + * @param {*} stepName 步骤名【必填】 + * @param {*} requestName 请求的接口名 【必填】 + * @param {*} paramName URL参数名 【选填】,不传时返回所有URL参数 + */ + getStepReqParam: function (ctx, stepName, requestName, paramName){ + var req = this.getStepReq(ctx, stepName, requestName); + var params = req['params'] || {}; + return paramName ? params[paramName] : params; + }, + + /** + * 获取步骤中调用的接口的请求体 + * @param {*} ctx 上下文 【必填】 + * @param {*} stepName 步骤名【必填】 + * @param {*} requestName 请求的接口名 【必填】 + * @param {*} field 字段名 【选填】,不传时返回整个请求体 + */ + getStepReqBody: function (ctx, stepName, requestName, field){ + var req = this.getStepReq(ctx, stepName, requestName); + var body = req['body'] || {}; + return field ? body[field] : body; + }, + + /** + * 获取步骤中调用的接口的响应头 + * @param {*} ctx 上下文 【必填】 + * @param {*} stepName 步骤名【必填】 + * @param {*} requestName 请求的接口名 【必填】 + * @param {*} headerName 响应头字段名 【选填】,不传时返回所有响应头 + */ + getStepRespHeader: function (ctx, stepName, requestName, headerName){ + var resp = this.getStepResp(ctx, stepName, requestName); + var headers = resp['headers'] || {}; + return headerName ? headers[headerName] : headers; + }, + + /** + * 获取步骤中调用的接口的响应头 + * @param {*} ctx 上下文 【必填】 + * @param {*} stepName 步骤名【必填】 + * @param {*} requestName 请求的接口名 【必填】 + * @param {*} field 字段名 【选填】,不传时返回整个响应头 + */ + getStepRespBody: function (ctx, stepName, requestName, field){ + var resp = this.getStepResp(ctx, stepName, requestName); + var body = resp['body'] || {}; + return field ? body[field] : body; + }, + + /** + * 获取步骤结果 + * @param {*} ctx 上下文 【必填】 + * @param {*} stepName 步骤名【必填】 + * @param {*} field 字段名 【选填】,不传时返回整个步骤结果对象 + */ + getStepResult: function (ctx, stepName, field){ + if(!ctx || !stepName || !ctx[stepName]){ + return {}; + } + var result = ctx[stepName]['result'] || {}; + return field ? result[field] : result; + } + + /* *********** step request end ************ */ + + ,/** + ** 乘法函数,用来得到精确的乘法结果 + ** 说明:javascript的乘法结果会有误差,在两个浮点数相乘的时候会比较明显。这个函数返回较为精确的乘法结果。 + ** 调用:accMul(arg1,arg2) + ** 返回值:arg1乘以 arg2的精确结果 + **/ + accMul:function (arg1, arg2) { + var m = 0, s1 = arg1.toString(), s2 = arg2.toString(); + try { + m += s1.split(".")[1].length; + } catch (e) { + } + try { + m += s2.split(".")[1].length; + } catch (e) { + } + return Number(s1.replace(".", "")) * Number(s2.replace(".", "")) + / Math.pow(10, m); + }, + + /** + ** 除法函数,用来得到精确的除法结果 + ** 说明:javascript的除法结果会有误差,在两个浮点数相除的时候会比较明显。这个函数返回较为精确的除法结果。 + ** 调用:accDiv(arg1,arg2) + ** 返回值:arg1除以arg2的精确结果 + **/ + accDiv:function (arg1, arg2) { + var t1 = 0, t2 = 0, r1, r2; + try { + t1 = arg1.toString().split(".")[1].length; + } catch (e) { + } + try { + t2 = arg2.toString().split(".")[1].length; + } catch (e) { + } + with (Math) { + r1 = Number(arg1.toString().replace(".", "")); + r2 = Number(arg2.toString().replace(".", "")); + return (r1 / r2) * pow(10, t2 - t1); + } + } + + +}; + + From 336c13f86c9c4adadd315d1c1bed146cc0ac6e8e Mon Sep 17 00:00:00 2001 From: Francis Dong Date: Tue, 24 Nov 2020 15:59:14 +0800 Subject: [PATCH 11/14] check service id before matching aggregation api --- src/main/java/we/filter/FizzGatewayFilter.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/we/filter/FizzGatewayFilter.java b/src/main/java/we/filter/FizzGatewayFilter.java index d6c4fc4..ae72814 100644 --- a/src/main/java/we/filter/FizzGatewayFilter.java +++ b/src/main/java/we/filter/FizzGatewayFilter.java @@ -74,6 +74,10 @@ public class FizzGatewayFilter implements WebFilter { ServerHttpRequest request = exchange.getRequest(); ServerHttpResponse serverHttpResponse = exchange.getResponse(); + if (WebUtils.getServiceId(exchange) == null) { + return chain.filter(exchange); + } + String path = WebUtils.getPathPrefix(exchange) + WebUtils.getServiceId(exchange) + WebUtils.getReqPath(exchange); String method = request.getMethodValue(); AggregateResource aggregateResource = configLoader.matchAggregateResource(method, path); From b1474fba97c710a75f48a2a6d21f370bdd91dab1 Mon Sep 17 00:00:00 2001 From: Francis Dong Date: Tue, 24 Nov 2020 18:08:25 +0800 Subject: [PATCH 12/14] add script exception handling guide and roadmap --- docs/404.html | 6 ++-- docs/aggr_config_exception2.png | Bin 0 -> 128913 bytes .../js/{11.a76c2e4c.js => 11.e86eaecd.js} | 2 +- .../js/{12.f815cfa2.js => 12.4047a547.js} | 2 +- .../js/{13.fdb2bea3.js => 13.beb516ad.js} | 2 +- .../js/{15.791d6b9d.js => 15.0358b10e.js} | 2 +- .../js/{16.4ae255f1.js => 16.f0131aa9.js} | 2 +- .../js/{17.32fa8ea0.js => 17.53dd322c.js} | 2 +- .../js/{21.081e4e30.js => 21.dca6f5c4.js} | 2 +- .../js/{22.0c08546e.js => 22.db62cc12.js} | 2 +- .../js/{24.9c5c2990.js => 24.dc881ae9.js} | 2 +- .../js/{25.aead8972.js => 25.bbf8bff1.js} | 2 +- .../js/{26.b4625fe9.js => 26.70321f43.js} | 2 +- .../js/{27.20a7e33d.js => 27.505a813e.js} | 2 +- .../js/{28.3d35b618.js => 28.2160d3a0.js} | 2 +- .../js/{29.60b7285b.js => 29.ab810898.js} | 2 +- .../js/{3.a51774e3.js => 3.13d0117a.js} | 2 +- .../js/{30.7591e88a.js => 30.37a581ce.js} | 2 +- docs/assets/js/31.35595b86.js | 1 + .../js/{5.abc10683.js => 5.a59b20e1.js} | 2 +- .../js/{6.e883523c.js => 6.b5dc0bcc.js} | 2 +- .../js/{7.e3b70354.js => 7.d2312c9e.js} | 2 +- .../js/{8.a4432ff1.js => 8.645ad4e8.js} | 2 +- docs/assets/js/9.6a35b918.js | 1 + docs/assets/js/9.b1740bdf.js | 1 - .../js/{app.60575df2.js => app.307fd529.js} | 4 +-- docs/guide/admin/index.html | 6 ++-- docs/guide/aggregate/configuration.html | 21 ++++++++--- docs/guide/aggregate/index.html | 6 ++-- docs/guide/aggregate/overview.html | 6 ++-- docs/guide/benchmark/index.html | 6 ++-- docs/guide/index.html | 6 ++-- docs/guide/installation/index.html | 6 ++-- docs/guide/intro/index.html | 6 ++-- docs/guide/manager/manager_aggregate.html | 6 ++-- .../manager/manager_aggregate_approve.html | 6 ++-- .../manager_aggregate_approve_op_log.html | 6 ++-- .../manager/manager_aggregate_my_apply.html | 6 ++-- .../manager/manager_aggregate_op_log.html | 6 ++-- docs/guide/manager/manager_api_auth.html | 6 ++-- docs/guide/manager/manager_app_id.html | 6 ++-- .../manager_gateway_aggregate_cache.html | 6 ++-- docs/guide/manager/manager_gateway_group.html | 6 ++-- docs/guide/manager/manager_overview.html | 6 ++-- docs/guide/manager/manager_plugin.html | 6 ++-- docs/guide/manager/manager_role.html | 6 ++-- docs/guide/manager/manager_service.html | 6 ++-- .../manager/manager_source_statistics.html | 6 ++-- docs/guide/manager/manager_user.html | 12 ++++--- docs/guide/plugin/index.html | 6 ++-- docs/guide/proxy/index.html | 6 ++-- docs/guide/roadmap/index.html | 33 ++++++++++++++++++ docs/index.html | 4 +-- 53 files changed, 156 insertions(+), 105 deletions(-) create mode 100644 docs/aggr_config_exception2.png rename docs/assets/js/{11.a76c2e4c.js => 11.e86eaecd.js} (97%) rename docs/assets/js/{12.f815cfa2.js => 12.4047a547.js} (99%) rename docs/assets/js/{13.fdb2bea3.js => 13.beb516ad.js} (97%) rename docs/assets/js/{15.791d6b9d.js => 15.0358b10e.js} (96%) rename docs/assets/js/{16.4ae255f1.js => 16.f0131aa9.js} (95%) rename docs/assets/js/{17.32fa8ea0.js => 17.53dd322c.js} (98%) rename docs/assets/js/{21.081e4e30.js => 21.dca6f5c4.js} (97%) rename docs/assets/js/{22.0c08546e.js => 22.db62cc12.js} (98%) rename docs/assets/js/{24.9c5c2990.js => 24.dc881ae9.js} (99%) rename docs/assets/js/{25.aead8972.js => 25.bbf8bff1.js} (97%) rename docs/assets/js/{26.b4625fe9.js => 26.70321f43.js} (98%) rename docs/assets/js/{27.20a7e33d.js => 27.505a813e.js} (97%) rename docs/assets/js/{28.3d35b618.js => 28.2160d3a0.js} (97%) rename docs/assets/js/{29.60b7285b.js => 29.ab810898.js} (99%) rename docs/assets/js/{3.a51774e3.js => 3.13d0117a.js} (87%) rename docs/assets/js/{30.7591e88a.js => 30.37a581ce.js} (95%) create mode 100644 docs/assets/js/31.35595b86.js rename docs/assets/js/{5.abc10683.js => 5.a59b20e1.js} (79%) rename docs/assets/js/{6.e883523c.js => 6.b5dc0bcc.js} (79%) rename docs/assets/js/{7.e3b70354.js => 7.d2312c9e.js} (81%) rename docs/assets/js/{8.a4432ff1.js => 8.645ad4e8.js} (97%) create mode 100644 docs/assets/js/9.6a35b918.js delete mode 100644 docs/assets/js/9.b1740bdf.js rename docs/assets/js/{app.60575df2.js => app.307fd529.js} (75%) create mode 100644 docs/guide/roadmap/index.html diff --git a/docs/404.html b/docs/404.html index c7c4b5b..56f276d 100644 --- a/docs/404.html +++ b/docs/404.html @@ -7,13 +7,13 @@ - + -

404

There's nothing here.
+ - + diff --git a/docs/aggr_config_exception2.png b/docs/aggr_config_exception2.png new file mode 100644 index 0000000000000000000000000000000000000000..fc5c51dbad6027b2db8843de94bb908393f1b5d8 GIT binary patch literal 128913 zcmeEuV{~QPwr*@zSTQQL?TV9%ZQHh4QN^~kVw)AGV%u7=@pA6Fr@g(;-S7AN^HyuC zwb|B~bD)ooZ+yMa6(Rpa91#u&4g>@QQBvZ&A_xdX3J3_e77WzqFCW3aWgsAM>lPv+ z@{%GVMDmVyrWV#FARrPENh#3kO3PpTr#g?LlTkpa@;HRJK?{QkJnizo#0v_;G7*<9 zp=fCLHs+E9jt0_)Q?|5$)nN_<+MrtN>%@r)X<)&#E8l~~*0ck?fIfB?Zp?nLX%P2c*a5>T;ndV1cVBm@yDL0Ii~?28Ol)zwi1jm186Hr64h z3%g91zMgLSeE{-0N;%SnN!Tq@-m+n$beo{QK_p!n%67`8B zWO7gBP;hxf{*hARS3uQ;!3FWBaN>+t2KlWTp7pC=R&*z>AEoKbRWM2L4T|e794Bw^ zuMT}(Q`3cSu|(E^k3T_kr%_DFKgdi^Hg_n-cAYrO9J6&76Sq1;6dj<<20vQaKD3xw zj9Iv%;)F0IUP)18#qR+ed^GZt`FnBGUoo$XUrW@9Zep_ys^@47LOt++f=_Evak*cA zpgz~_JJc;Ju#BfXf1j-RMkAa}Bf2w~ZV+S44xr`Jw8gqyzJ6>CEM59Ki8>TKUc<`A zY`-upZJY9&Wbf`q)Hl1{!)M=WD)HTIPO8n{aEkX&qQNFE`sQizvcA$tfs@QE#SPH6f7t6cas zP-Hec0^9)NN zsKd&0xsSw;zBwbcfw_o09xyHw=FqW9RsI8u_t^5BM<>ahZPk+&Zm`^NyMT?Px6-%l9acS7cEs(W-AAsk311v z7rx6AlPCP6&WbT1sFkZT{eEQ5iq(nU3DpU!6T=^FE37BDDg00%{zs1qJ&Jq?Z#T-o zXos;Z)g)C|hN>9K3Cs!A37RF`BW%#{Sly_Sbb$~zR<^%-z_#yVklk>#W_=0t3>zs- zX*g|H+aZq=i5^!id^MUUisxs01nz)OPr@a)J8lO9KPW@r;jZ*m*rnMe$JNy3E(BR1 zac>%m)E25LN)rkaiY6=vOi-{xKJ%Z{BdI8oV$?;{v2etJp95h79N)f3#_oNGqkxt4 zC}f^dm@!clI40Eyu@<{0p@=uxo7mHI#C;-oLJSdR%6FIlLb;qck;pyjF={jl4Ot#o z1f~^GQlpwDoF}n4d=??NDo2ZCJMBFo+vTDg{ACO2$AIGlNqESCk;dCuKCM zY+|)9zb~^dI~tY2bsEPMXB%gX_1;2z4m(XcKEqQ{$3goBUIB% z9poAG5(*(woY!NYVi30NMQT)_UVtbzAto|pIb^-7z3aIfMvji=mQX}KPu?tBTP!o{ zJlk2UV_K8enbuR;cNWTJeW6d!x@on+hs-i%k!`Mf*FgYZ2RTMEoWGI38E^a5IL&U^ z`pL1Y_ci!w^}ucX!_veq$-t%OB%m?U#owjNrQ*&Cmj$<4He|v^E3yi3uDOc2s^)s& z>fP?++Ig@1qW^+;e}1orhll?S2@$D31}a7}#tY9YmDLp63GJp1ZD?fHqH30^Bz6*M za(Qw%^TWQ@Ueb+gkGY}89n`Nk01~{~vl?%adXb+aR4ab$?@_~ZjnSeJI zC)SKsNfqam@wBKUsbt_L_|S{N3^1>2vq5Pm03-qaAjHTq&vDEd?(*y^>$>YI@V)n? zd0Tm9dJlMCef3(>w5D&5;ltU&uHoJiCgNgbuHn6ujMIqwR?3Ergaore@X9#A_#J%) z4^DVFZ&idaN{&6x1q{+@o#L7l6!f--4wDFwDJkQXM7*aUo}EE z`eJlqxH0TGoIG$pI1#Ib??$Ifs*AlD?=KxLSt^OGbyRPE*w_30WuR}M{bv*wou0Ev z?a)rtU`Yxk{WdLEcCcimEO+8<8ro>tK@?ei!o#;%$Ih1a76x~M4*U*-E}HJ(586St zqHiXY^K33&CpA4f^3>R>e-Ewu;RsHIpYCSR?{7p1ZKHN?$@qHJ9oh}A z&v5k^xN5v(cN1?0WS(ShCNI?MDyOP<0Mn{!P4Fs7-PtZxKbzi_Uf%AGpwsZvnZ>tw zyCl8%4_BYF=LN8;z>dHGyVtHV24%`b^m}XjW%(z%XRYn#ELJ?A7jF+Y$vQe^DGVs-)W{z|HGs=}K*TeWM zHK}tc8aGt85!bsU$fU+I_N7jjheJo9r!2Us$RWOTFZK(M?v&<-1O8Ya#3aq6!K9on zEZKQFId)gwa&NdkN6sYXMl@l726|>X(Vv4Yz5N^=-r% zc}o3V{W?=v{Dj`bzD)dzkL}k$FWvNx*JI>Zf$G?yXr!+Aj&%1=@b{dt((G!tI@~uz z&^_kO@!oY5^c)sMm`2FMKj`bp-gU-u;k1l3%TT2U-p!x+J2Mr<>04%*Do6+dCmE#w zVxxo~9x_NHJjhPp@w=x~?y*}S71&2aiPt5S1IQLgz9BCNjEI;C!OTn(F#uZs*((v+ z-^ONtSC2%twlOV6)KW|{VJ0GiL*gTx1#(MzYGA7q@gq8;*>)4m=Q$h z&%%#i3hRwk9$SRW>o*@J(I0dAbznS~a&HvmK%5`UAO4h|c$d>eUD8xm7KHlq8U_S3 z%mM`B^9uCyi}U#f0RhVe`}Z#pDY@YPz6RI&S0h6vWd;a{Ac*95A!T>avvp{1B@-;D z%Y;G`^wEv_vnpm2c$jc&Xi6mQ(o#--=s*(Y@5*aCAia>0obvLZsMx$syn3!2&TJdM*egr64Gryg%4qFI!*&!hgCW z>Iwgkme2c{8+)wkb(ozJq$jyp?hJHqdqugwYpT^qZ<@Lqv^f8X@+SU=KGPIHdS`O9 zuxZKMY*E{KVfu$G97Ytbxc+nK&jISv1y`qbG-}azB*h^U_y$~BasHu0^xt2=GU2eE zEkZH+i>5nU$p7h{TtR=3{vr?*{=$D;Cyb8&w&IbhcEaCQ|8JQP34XSMzz{0_T{!>M z956;F&m4R12o(MeBt*SV*Z%d7U2Fw{eOMW$B<~AX9JYE0cVx~NFD?8|k~KEB3Y(+1 zO|TJPyY9Da_OLuAX!fwK!urvSkkWT-ZLjwaoAUb-?8Dkgdd(tb(_zgwNr#=#ajbil z&j2-hpwp>MQ@QZBEZf;keuu2#_3}WmsB{aQR)l#5@4|0#S07%75NUqRxJS+IXuShy z12lS@%`P2n`jmlBEth1sU8DT<>z87awFa=x>2PwS)@ZmRmcg0A?P4vSE@Q~|t9zwR zyDA(8wQ*Nv|5CSK_g01JMEXMh&#sV{KLz4JUHod*+PdBKW>cfjcc%&7awW4=G-}nX zQ#^PvxvOK=@UzcrE$g<+?QQ^c23_r)-QE51G#1}rE~f+Z_H}yosk-K4yF60ynBQee zCF7^By1B^rXUj(KxP4ER@_B*!xM>czIopXyDrYkd)`nEaz>IZfgH~z&3(sSLoU3Q# zp4&V6WA%A@im8Y*fr}66E@j<}??;5x+HH?rgqh4@o3nYbDd#R@3;njois!H0hBCUl z@np}7;e5|D7lX;JRKEg7^;veOP+}wgx{FveHTor5wxzZyp+z?2f_<)+BZb1C8HtMw zr&ox2L#Kyaza-wmXR3;Ikg^@ep4FQxX93NJZR2$th-bxy7PrD5HKW$wWV&<~>|qJR zuL8b;6UHIqaT1Y9B~AxVlEYA=xNnKDfssXphr>kt{D}sk&;`EQi`9h6IhsgC3JH&i zpq-gVki+kzi2|W-y;Rfd-UB_RTBT{yajAWGGVfrNjZEhMGbV<88^5XBWDN60le2FV z=d$0Umkx|{)86RjV1m4-W}$KNFrCfnwJG2--}~u$!7}ZHy=n>(jD!ZE?`fsetNGy& zFHe6k5@VunG>Il72m17N+YJ14ryDR+B>j@M%jGR9Dmv2Ua=JH41GweU^QAG{f_@Cq z?*0Zwn9*@tqJ)%*!d1PzW{T+g{JO^~gp33{M?$)he*bO3)ZN42{CggL^&5Bl?+qhc zj|aUJ+Ld$m{qmL^rH>VV2jLGVAMs`$-?Fj9dJ>twZ2f@~-z~xj&h-?YI|i(--DxVs z4_5VZjREr5BYxjS(!TbbuG1_2zgarUJJ>QSV;^BY;m07$;d#L%Qd$*;tRB77u^C1N zul#0p&LHowgR(%ZGXZc!+;#!3SR7}i$RkSU+KR3xrogtD}R?rrM6u{q@lSO_1b!16V&Em*Zm> zugK=6pSJP7Z*%6t=2!)COOa5f77C0{*DRS0^$Ej~BRd+&#O8K#b|YGUR>*ToNXmz! zCwRU-Ovx=_s9DBpkq%jVF0)00D(T(RG8Lqw=lkgxkS) z_&45}eC^9L^hLEMX+p%LN&(H?`T@f?83j>+DgDv4W*Q~c)&^+-_;sCO;$=Mgv{M!g zWXI^SrNSy-ew^Z*07WD1f7w|)D)ti+gy?FM4U5n(J4nQZE1#$nZ12*0{ExSXoCjhs zBxNV#y?{|V<(yn$$Rvr>69^V;Vi`fUKPU4Q6Ak2R5BQ}!a0n6JIeK-*5kL{A&2*fw z<8bU!>)sbKHWYIM9h#*cUqd4It11$a@T6ri&n(;}5|F;u@4q8+o|cx>(U^69qaQ*O ze_IgGHAaL8;Z%bmyV^uAPi0nWX>gB~=1&DO`w>5S{nV=PUvn&YCwaG^qs9}xm=T2a z<0{pdGriEFZxI!pN#u!tZ!~`+13fit(^4*!_3dI2Za$C4c=_(TeiScXedO;af07s; z*WKJQE`Yg2Aa(}Zylf{E-JjUjuQ{Sj+kD97Tk^N4$DG~6lvQiL_>dj>ZCoa`tC!3O zv$arCqn)=%w%cb|_$}!1f-}RKiE7017g}GXMNNyHwR4O zv{RYod^z!Ko+hjSA-1ajDejJ8M%g@oW-m)>7(+oN7?9BwnX(FKkS<_;mi9_lipg;q zGe%5pvK%>dJogG7a#w$ko7AgTXWX9`Qfd&G34_;Wz7O5(@NhI{JjQ0??WV3Y?BHxsD|IvoHql7aoYz#Z^JQ` zS%yw)kP#ssE}mjRG%n~KD3#U|Acg3Sg2c{9Mq{_pVH!DAESn)S9h?iv7g)(J+pC*` znzHS#9{`8uop%D!iwH(xrT;uTh{Sp_RH{%A+N#rJomR_+9Oy052rmrhuGJ3*RXfh1 zEKG*ehqy`QykN!LZ=;!w8!S@FEo}Dz*Db>uta#zJPyo9r6r4%hG{2X zxgVKeYH+c~qp&E7l*}K>DV#sc4D>F?jQ~j1b z;%&FT;>E%YkoOktvRo1N6O0}C-r&f*soRe!QBE_+0S^+Uaj#pLLTEmAu-yti&N}Ke$tr+f&htdnJDLaq^@5Ob=S#2HZ5?;# zr^R}Wd6mOmAhv!I_Dd`9gyoBppTBvdPSMsGrJr}6tYh1`%2;T)ZAuRIdwEpEeB{K0t%b+Pl%;#g)k2dsF z039aPuu%^!un3e+9?VL0o8zzIlqbT6T(Cq|fBo=1-^q?7y$uoFN}S^?$$_+;`-+YI z81&e$wmJbBZg~XhXTNXZ-SuQte^~!raaF>Si@&1dN^S<2HFqkkL%_cMg_hm@7B9l%=@U*@17Q;Vwv8Bz) z;&Dqiy>O5EAoms#waO~Ay>be23duI!A5CIWkuJR$tK7wqy*9JGPK?>m8KyUBxVo>X z&pKd${Phg)5qU43-k=FF(W;Q|nK7x;br(5MLsdjy;L>%g@*E2}6jPx2ruOZYZVT|G zf0es%f63jWDQ!Km-M5YNb`iQdqT8HEzi-V#J8dT<8R;AzqXm;t>2F5{3p)R5rWP2K z>N(ZcxQW+ZEWg{gBD3Ji8F-X!DS&>}T^|ahEqfi_UwHhC2xILs>WyK%g7*=p)mP z&U0^Ahu}%wam}k$`Cy6|$!Q_!BS+9iy4~Yy)}M6AyD@{OXkXqh%Z98M$?)QVbAzLL?ZW<0)u_+V#la93H=Bc|y z@0X^JedZL_g>HK1YSYDv?$$eMlph)ZpBOQh=s0h#fyC~7Z?>h>(#~XZK<&t*ZT6db zjS{#k;xfEtDyvt9w5uh?+&db*N14mfi^ZKf&eCX}Q^WcOm1D0=;5k}~!rxT4jC2~P zma;cL1wqpo9eO0?Sr;ap4tj>S0rq!IyVc}+MJ%S zT!=#XeWDODG?7|-pyd-73HY?~ZyxRe7zQwmjGc(9RC-+cB-2cyb&Odsm?~z|CGF|Z-$GmRQ#QRbZ_jJp{YK#9p@3E#{3VD&y8Z-7_Ahll_C!R7ECstd!KckIZ}e4v~RY zeiIp}9x88qJX3Ta!W4+2tesm94jvtQWq=2Y21aEK_&jDDv_?IiAN?sPj)#GQ*|3*6 z>I@oAT?u~YO2uq+IaQrKEENuc+bB~~&(=2gA0@RS>JY36?vn1+{nX?um@cR<##NB)HJ-%e%A2dhw#0G1O+pJmv4B!4omXN!eZ7!h2MG(C8(&hm-}P z){(m)1ubiR9Fw|_%7Bv1Yz9L2&?>oL(Dv}xKq^s9e9U=Bm@HJ-{)tdqbmy- z3qF`DC$i!xl^QMb$pZ7D$kX5y&aYp2gz@v~!Ps#;^~^&$gTJRLqjJf!4Lkk2`D0P| z|Gcmdrbog2`K=m1g&)%2cTdwOaO{I77-fHb`uGlZl(jg5tl) z^uKs6BG>?l9Nl8c%DzEZuo}ab0Yd1%;gbLMNL!@SZGr2zT6Y=)?LrXK37Dz~DS=z| zsDCq$|2;tswOl)v_6ABbELBFbHx>|F?A}Pk&IH#TmcP=R|0eqU!LU&D_h%seA6fsQ zFZ5i&88C#D_@?du`@=2HphW!tmz6hsGLVHfj|l(Rbq^#23H>E+&cCD*R}4lsJXCUg z-+I-6_PERcju!9Qw#NL|=a^$aXi}IbTX(Ym8W8{Ou>)$*YR=cOPLbL>caZ+Rk^f${ z@h7tz{`)sVZNZx4Kgn1y;1Vs|o)d4oS#6Em=+$_&;@Rj13wp{q;cELHwWQE%*rgUE4h6T1;HW9D`r(pS4&NQoS`%RE`%p zz@octd9Kdu`S<8$5r|JnaGy8m~w68vsy{jF$~6Q9BHvheqaldVI^?Vz@R z68zHbQ9g-{BBRu|VUwrh@wpCO&i}Lk7zLvHEd?&uox~RHG}6|ZRhutaG$rWNsT|(} zrq$~4BY1vQDsGs+CFVqe_s)E>i)ci~iE*#<_dbk=NeM6KuTYVNQ4^o)fU}LJlMlxP?f6hc8vKdDGJFs0 zzA03%%|Gni*moRxWay5^Uv-oCJYv4xyYz=5GGArbO}q~d3_S9=aS_mJHEH{1a4EqZ zagApzew@Ifbw7y}mwN<3AvUls{5omJ!o{_szNti2CnO1WQ@BJg1@9CD%C!4%?HB6A? z^YV~UW42V2vR^CyBGG7>jeI_Z>@MW{VpFW)I>qOf^YHwy^h}GxZqa7~B5=CsGm~(A zOkwm*E}QpyQO|FT#V6;^YXVsB%VHo^GO4ql-42W&zU|z^ed-!dXB%tZu;KHRc(_>a zhy@2$&Y+xTxoxl!s}@Nmf#uwLy*`{RU*FF9yd{&}ZQZZhC6wfNUU!syJnShkd)?zb z9rYvcomAldZo9+XlSceRmGfOE)L#KYv%en%7+==9b3U$i);gXJv_4Z;|ne#>8bvAT297Xg=D zIYozJ)B7b0;p=m}^ZCkPFgQ#AH3bCord)a+NDAnl2E;@Eyzw#P~cTKUQu^VtfZFoIYuNTkknQLd_ zE&27(3V1(;pKWw%A>s2H-&e_IERg^1<1XW?{)1BJ8{{d((e5^-tE7YexEEg}-PpG; zFp|bn;$itn1CaRS%4EVrA^l$8!!BNglv+cEOOKx1$JH%LLD4gVqO;mvNBlv--?D|x zciYbHJ}>;FrA?N;veMmb9}fe&GxdjAzGLxTmm#5{ zr6||Q`ek#qfL3V znyh~fN++l4R|D(cWGKHrLcvJ3yR>U`&F4I1yRFj^#=c8@rryw6(mfEugn~kUe_1E* zFUtL{E%7%rP$*BN6eiu0=+j$@9%+AvK~cAc;VZ!}X# z_|}({OsDlbeo$Jb<+c+_Bb7Y#YIkph8}XFGVzw>XBMSMgG`?;KOD`&+dBb(JpPPK?tR4W?dacg?)xm`9&kdz7X0_n8w z&m4Ci9h5}F_9p-qQg!G?z@OYIMUL`G(#(Bw{P*)G5 zm@yzxQ+Vc09 z)5B%I=JrBw&@kRb;Vmm^(NP1_;Fd68dY(;Se8!&WZ6%5GykmR!|U;RPg>p+c$2Db0q%3ph0% zs}>jl1qU4q5l;3`aVOmH^J6H}V{o5Oa3kvsvM@R&f zkL7pO6-6(`-*5x+1!ikcSz<@lDwQCTSXY+hnNori&lmU*{Ca$JKgVaEm-%($ga6E( z#py7^Q2KL@K=wcKDkt!{59dzcx``Lu{kf96p>=v@HRIDC-NPRVIlLY-y!$h5 zMg#UY;)eionOm!KRBOOx*giqCEAsuEi4Nxd_KYGT$4O$%NYbD+^O0K#tgq`}Yf*Qo z7&Z(&Iqd^-hN+F?h#QTL;!E1oIio5#tPAvTI7 zEn1Ey^^yR>9kT98h!c+_k^Z8@96|`@rQsMA`gcQb=!Vq2VK(~K?u|h^(tR)AcbXwO z7s(&{rd>Tvu8>}iK79hlKTA(bJO@B~jU7y6>}N!v-3rVla_!vN ztTf$RV1tndV=N^D!)K|i7aPpUQeE#q1L!mVe&@#sMUE%1V5dm4v7B7nQog$@t(eXI zQXY8Ig$(){oRtj>1bjwt|5m^@gj1)uMPv`jv)11LS!zIlF-(LfPfVz}Qyfri<_ zN-5%^0Ng;9s7R*ktWcS@tnq!zVFB*zVDC-R^uJY<*65j2ZWLNLQK^&{dVj1pU-u&m zz%FT&x!DxSN1fIHqEDb%wC6CVAXZ&4s^RVisMS}fJ;&K}Rs}_lCPG?%{pFSPkz0LXT-P55SOfmky$kqp{jlU;B6*Y)Hi&Y#un=HSw+$-HY zl{EO0r{BHgINDTTD&~K8u&Mnsr%eQl^`nn4lF2vYsr_A{GZdW~{k2cFwieoCa8v~$ zC2B#`o2F7}Rq8v1>SXS7kr?XK?%VLX=UwYSbWG}b;)iQ{kqmzZ-ZW#G8+e%UtoC-N z$B(jVfCoKsqLg=tgoe(dW*7eg-4)LF&RJsNIvwq75}1L@`PxWed*K;>V9i%t2EUfu zp*yUIIQy1!n$;o`u3tReH!`47X?=r$XjUwxYA9p^l1@U;0p;I?##X5Z&IeIukr={p zN9I!)ThlB@N2qexf#)V;2T$8KHWK)c{6``6(iItuAqa?7zx0g;2Jz7#sPhocrYZoP zrqw8JDfftd&aLf@#E)hxG$;EhVPn`?wx(~w*Xz1X5^@-`&D{9NY7_9TY@Aka(HZP% za0FH>s$;5jjVa1pW#tB`Y|{eN_OJK2>4`asD~$kVpNdL2dgbjcUj5v77`0+8z`S(n zOl>He4N|NEQ!s!e4N%b)UBw`E zG6JqFo=mFHU1XxvPw1Dro$n}zt@4__~}c1A_ZK)pbxy-6|8o6Bb2VNKK6w&2!sU8`{rs;|f% zFM^DByTuLmh1K+zG{45#%yrE`*1$Re+U`W%YPC$IRBLs-4uQ2kTDz$n!`pFU^ZS)| zuCV`HbDD_bH>ZKpY7Y&)pg&6eaXi&^87Bofi>-TFRl(dIKgL;Gg{tB=Ce<`W*;Fd> zY5>hA@6l)I#38JBURKpgnC2nqVmH|BymLMEQ}B)Dhn;>|j#Bkl5ax0mjblu7$=LZS znhWfnpCsQYT*R}9fX}^Cj}U12VpV94qr9B4OXyo5a13%Qk`GFSV_z! zBChslW<2T4!TP4#E$6|pL++Q#;vY#OkY9@@406KC*OU9RYk)r*r7d%O9t7xsZs#)^ z8D_u~0EKVCO9fA6U;v}>#;|Is+?TI>V;TUx?4sSY-Oiv`xE2UhWS& z(Pu9m_am8mgX~yNZd7H|{Vhwa(m7aS<*Py%tn_*2(W>*!==#q${ifJg8S>S5`qgRz zdQP72@r_sJ^!7lrK9g4gL$i;fkrmTVp}NbB57Ya2=A#=GY79>{L(cWMEM}8472BN* z$o!AFPh&yAF32B}w?6c9FD-Rj(7@Qa(K;SspNLIQbHx|{A%z^10d@9wbC2OHzPE+? z^h#3io&Q4-{)?cRQ3X*EJ6!;9*aaGbRtV6(w?t26V1HQHZOn3O^>JwTUF(^RCldN* z2DWefDKqjClH0P!ANfwVT|Xwr?qCjLm|&}CMUuap7|MH8GS^v5VJ}2T7BzumJ-%^} z{7bXQ`6!V*@Y%WII-6gh+s<`leREiv|4loF%JsYTMfV6J74KI zw8>TC&l8-n~l_M`&h*N+vqXw$)h9@8`E8X8%Jz1uaC^Ud9i@k!G@_M9A@oW z1eJgfCdzfnbv+2bPBzN^#KDBawQFJcFxrLD+Spsp>D5uVw#qkIpw=yX+i@}Ol$9xd zj|l1Izs{ODe(z*zIxa=pUgwP~IfrpiQYUvGlW%Hh2Q~*5x44>Z&S|-6%*8YN zQ#pD_1l*}}(i4u#(w*!(E@)rY-TM(&%SJP9^{p}1|HdIDMu9W<^vO-9C;{evtqdqmG{RRx$b!f zm99>&hf&FO%<@DO^=&EdE>b`!-4y@oqMJhchB!m1MH@h=Q4SR<294aVYroZVYiIE1 zM4iCLqtZg9#%?o1OTN~6o6Bpm&Nw(L?T6{k;)-C0fAe8H{0JcC=aa@n5>0d2T1MeE zSq!v_H@3MhfgA1Q+Tnj>=+7Y*s&y!Gjz!b$L#}Y`jtr~&qJPTK>D4M)o|=u&XYr(4 zI0p2_H;S8#B_?A*^V<<15ipNy;x#pYCDG<~T&Yr8`w~P{;(H(*g7W+=FWo#xb-iI$ z-YjfVRkI>b(&zkK2~a3oJ-r3-mhjBs_S?sWRHi5Bq_C0u&Zgwv5)L87@dSZFnbV-H z;BJi&M=EJXipZL44V ztK_v6XU16q20u1iDAg#%00&Nk)L!78V76zpB*p29mt_COs|oAu4$D(c2DPIx`7reo z71Q8PH;%s!n$awQa`s!}{b1XhS%!4=>~0NpywpMMhyr3cV>C)b7D7hLQ-XnZ4sVw zhe`|mrTettq0Q3FI;g&Cj!o~eU}=$11m=jlQvft@K6o*AY9`3Di2GI*=aWadfgf4H zv}MXV9Si{9-xhy1|HyyY??>KvU}tS!=;uDVxqTt@OC_HJhvGHkGpW7|eG`XNmXV2a zYjqiB**}Rorr4j+i^TqPQLJhm{k6@u>nob`+6IU!;_dwq3nWgsmBif7B1H?2mVFQ` zE|+suvO_L-Gi4s1mnXLzg3XA5zB7Jb5peg~@l7=w*n)9N&x*Ft^ zNei|K?5b~dr)qtK*Ap1))0OR#8X0(h?uoUKyi!r3@c2v;)`tfmBug>-k~Yb$jLweE zvWcLq_&0vj?|%tQg9jz85k?6qr`Qa5OD|O`tgki>J0!3@V%&}bdbaqf3(y#r<8@UA zlsRG_!LoS0DjIq}S#gY!8jhFdU4`df@&x3X?J|2kR3$-GXQmW3Cx}b=i+R@>xF!8GsH( zseF@rQsxsD&@$#I9H*jX4}@u=m| z5CKMwZps0Hy%~#7U2>Kic59`1nOr`aH0Aflb9Ez%$|d(~=F@^1)qYhI6NK!&1jQE^ z)XEYEpD($>fb+PVP`cfnQ3a?$bu7IJhjTdWd{^QNEsMf_)DWFM;4xvGI|r^e%SB?) zoiuy?G0Yx*x#dF0^s>$g`YU6JF5wk0q1BWww!Ua-x7yNT#JpdkH?A_C@ciM!VsrrL zo`^AMl4*(kRHz@BE@RT%qKHbBl@<mFqh$Y8-4Oyxkh ztQrp3n#6(0`%&h?l*Jz&aIjh00#|Z1D<_b#ew_c7Qe)Qc24sqrwjv518{r|rtFxFr zfWKh&gj)9%mt%1maWg4lmu#Z;mA`l2>H$sTvPzC}KUc8>Z(_I6JY{8+i@;qFYW(4p z^~G%Qo9D<(kz%b-B$d`wH3-=vOw& zhBQ^S-9-!XE#X;?sH_!vJn-4+N)z|YIJ)g>x6jvz7inc4RSU#iI`f5KZ_G~@Y>IJ; z6^o=i&rBwmAy{CRyocX9FJ`~UfApYkuOSP(o2#z2I+djPx@y~?&>BSQWpTTBbNr%z z_^j=xeZ*n8M+3g(Va=(&?c0Ue-C)r&@>O-c-SgBV#Z-OLs2g_-cSyp*uiDPQg^5?* zBx()CuBUq~r4ZFJMNto7k#_k_;QGTx!snX=lAC7P_p4QbutGD}!8gGKa#I2inbo+j z3}n6x2jG88Hf-fXPWO1Nx7|H|Z79*@dm%)lO`_Eh{;X=C1Nt#a5uD$|HA}(T1s*#+ zYTw^X&5nER#Ut+{M9JZiR8C%hvUAuKz5y6R zE?YNw)waA;af^(&w_a{^iVtT9vidmA7)oxdfpKD<<0)3w)1w5+CtLkaMUfc$0nis5 zvI(d)GS9y8WnYe0AHK3+lnqxky9ZHhzTI_N;su6&a?i&MAae3IPguLgx5I>E(JOAy zyWN97_Zxm#^d${UX7Nz)xSlbNRUzNGGx|I`*CRv^#p3Z%XK>gpNPU$P9Vv+Av(2Wd z#9&UI1^xbV3RsLY&C&Mr z;ko&F^vPz7JC!DTN&r&B7QJt`!xWVmY%HQd!J#aXOUjB3f5VMb9(vmWr+q9+QvM7) z{x}as^wMZ^1Cn!C3D6+0av>w6jH7{WGTK}wZTCZd7Pnd4$!wZ+T0yjb$-3JsPpa5E z`${JwW7xygC_Y;(yEljhJ*uWB%Q$;bS>|LfM}5TQd>Qxpu(@OG2I&_7gU1PteY71y zgiMUtS1hbKcqfq~zMs{+$*h)`@w5skhV|U+dIRGizItW}3m`)6%#*Lh!YV0B;cnZU z5h1xHq>$MaG4i-g6wYln9{Ca~Ef&7{*IaPiGZ-ZiXL-(xYPDun&Yv?+lS3s@w$wXKZMO1jJn$B_zZ9z+9~uf7S+Hi@X&l&wg7djDrW>i0uaEMEBYX| zkplDCHLHw6cn%<+&j$k-)ZHfNghT%j#xkAu_j0ITYh95L61AKxys7R+$f7@_vA6uI zEQ)2+ZMMYa`D+*BAObs#{3i%;NVRnRscH#%|JC!Z5p}_`%=agOI4*|`v)XO{P?g8T zX96TSQ?oaCEcE$4BJk}EnU}Kj?!>|6^jS?aPr(cDf>weZT33Gr{z=)fK+1MH+=T(| z%=)=E#GYf3d`&O>a+|%cp3HE##nLxaSKX`y>}KnIKh|kQIPcb+-q>E-=i4VQ*4qoM z7ORUNF#C#h9|X*^t&;6c1c8wqB7bK@B0=CVLJ|FBe`Imn6!#L#j{^8os;yQvHT70U z8&rB_;#Te2Rm|!WFS`yKEV@SnA%Awn`T+HdWm;ltkW$!B8v3X;C+al;OYFiWKlde; zRugc(bOO|Zy@Z2Or9y7O?`TWB%hjAK0P_N$qzLP51HtSe3W5PqZf^t2Evao~fOv1P zulRzbkkaM(N*vB?ucdi+ft}r*nNZ^txMv7!uo6rgJ*)iSjmZNHR{_^g7qa%n)#Id{ zTc+akypv&^g{D}GBMeRq#CZjGS@w_hT3t)q1W&%e^1=-?wLW-u6l=bf-ydH$%lu$~ zp{KWk5I!}xd`Q8c3=(ufW?Q#97PwEk{9uwUIN^+ftvbM$Z`K_LxT@Ws{>hTAC_An> zJ?PAoOp&Hz=OngYbg2!UD3?0!8$w|4E|jY01-hu=>Z`F5|GrGoW8X%4Cc^lW&C6yr zpIEL^?v86Ma4T>3mDM~PR@%0EmpvjjmZO_?TH>{=B%5iXp;m!)b|`a&I;le9;%LqB zw2E)s(;aD|#Rs}Ph28}LpL?7YdD!GA$GuPKYf`+882MQcMhiq2W-k^PO$m!`^#aW? z+dRrR&ZhTG7037X>rt8s!`t9%M9XP(JT-t;jecH~_lM8ZR)4JVLpI-Gh;b@2R^?{W zoo?x6T_6vw$PwEybe3;P_jJ{U+Cp1EGo`}$@{KKUhgyYt?DL;a&KIX~0}ulNpEzJN zj4(QWx&BZBAd37uaYW!zg=zcg^A#qqW{k5*H_ciT+2;NmPS>aye4f!dlQEf^;9QHs zA9fY$wSlnwSM_Yd0Br0k0hR>^lBHWd1{cdk_RebEukUp~9HM4sR>TVnFOZ+3ljf+R z)vcL;d{;sX*AS-~g1^#k|Zq_9T86$x=ZLgL|4z<`9mm!(% zhh8(x({cy1#!Jva~)|Ha-{M@6}I@g5Nc^nf6Bq(h`+kd{UfP`bM@2r21y6hT2kX^>DD zhDN$UL8K&{p(LdlYNTPP`yg=65&Z62cipw_U3cB@ztNZXiT&(n*KhCrUKH~fo3Wqb z{UNd8o0&n1obqh2z&9s!H_o_}6EG=U{WWy}$?vMzk)%1&!_(+u#51}RQW!##Bj&%T z=>I&lR&e(Eg@i|P6HiVte{n}lIoBw1Rpi9);b2Va{A7_=6z-;bYs-}SN|;r7JN?-F z9rshPz_p@U%tYmv*0iz>g-DBLlhw4t`fpI3TzW&BqZ z>W?#!%b{eazC0V^sY*}^G?TkutKm*fHtdfTb>%TzaE?3Qb%Jx+ShsgKc}y&R{JPrx z6w1qvpYQYwjCB7lH4W5U!$D@*7dJyU^`ktwe^+eN8Gx)f*m<5|-(QGu7`wcy2-4nS zmMfRi{%wjJC2~rX9}rO36tnR| zdSuAJ`_%T!?+>2+>e}tU7&?UIT%qtrQOmu?I<|&37_T9+k8!XL_C$q&xxH+n&<`ie zSau#6vsmJvh`0Ul`vYuo_T$t9=};?V&)Xu@Kmt^Y`YGZkOjN|d97X=~w+CL_ag zn!bleJM!^kSi&Fl-vpHAlPA_{4gc6=Ws4-d3Sv83gA)YDQzRv>kUkf6RS%B8&IHk# zybV##^EFOa{#cpr{TTw_{27^#_{U#4$Ys(egE}UXx#$GHww3)wP8}UW=oOG4itvq~ z{B2gEjwGlf@4ntHBKwOgbC|XHKYzEzR)_wm7r_6{IRE$Fr5nBJzqxGG0x3L~_-mBu zh#ec>VHGplGY>RTdkjsdjVDYx{Eo>VW9eu=MvmtHXqtNaYkAGVU;mvgBYGmM4N$tV z7M#%kU+nrwE-&prvbxKQO3g>v8_5IAF;k}Kq${zbuzd4E#dcs%T6-4NZm#!gMAH*}% z^&C%J@OT5HQOs9@47zRjv%YS&9$ z$EgNy2I)pH!>aO&#KepZA+%8oB`cvINZ%A^TM3a0AX!{kj^TL#vmN$c`a~Skg09(v z@L6?+qL4lj`&|({(AA6}HztD8W|}Qqw|J%6&*g}N|0OMPX`#Fqq8NDBFAdhyU)UQD z_vU$nD2XxX)674A6P^qo;P!~qVFcXRF)@iHLR_T2Ge!6hW`8 zwKxM#z2cW3@*=fRoeA%K_@co_FxYBucZcGlC@aW(m zHRVG37ed!%s+qxWu33-|X8@AN3}19LUx6c;a7@ka4G(#7+kHQu@3BrJ_%_!d-!Z)s zGh>w?i7@jlM)O3C{n$wO&27ady1i_Nht|20sBpzGB($cud>qs49P=YyZOzJVT(L3u znuc|tqF!BTdO6$@1$>%)wqpS8=o$RhI-0+_L7CHL%Pp)7GP zXJ$e-g`O=GYRVW4^)lHHbFR^(hOeUcDq|SBlN+)hDJ)Mud2i9Tf?5KbXxjDKD#V(O zX`#3Vx=pBAc4pCQ8M-~Yb?a86xWirq$mMGR(XOyKoANu4?zY>k`HXL&Tl#IQEV?&A z)+x919P^c1Pw-Qb69ECQ4XYNSKqBd-oalV6e5-Yv7*UVlLTlvbt7E^yGY2BQR+6r@ z4mK->yvuANGF)qt5k<&G+WliHt1YnK=jLUhxZ4X46E>!v#XvUS#Yq}k%!X=g@jgcM zbYGouBcSg*EiMFWAa!<=V2`>c{l)pt?i+@x88;fU{@(5s4am+#i(Hd#9$gMTGsfb} z7cY5!j(3B+so~Jc@1(rC>NRPB&f&N0R91`^VKP$MmbNLIAdC0Y)J$-nxzvIs)}iq#44L~@pe2U+!HC`(A;<{6R*kWIQntF| zY*4YrZ8iBPYM?A^ygTE{9M4Ur%E_6`+{gq`bhvHJR$Jvb6vw^E51&$@bY**a$4j7Y z>o?4#e;>-5$W9hEeC3$~{p}@rjg~lrxY;|d0(Mm4oHz=ehUCTRk2%kT@>*_ zSFJaSt`At(GWg!whc{6Xjt%iHx8=+JBBtWALG)(1z#(-T+smBt?^nd<%X~vKLCWQ$ z@kS!zt8X*#%yKj(tosU^2HHV2Y}v$r=024^TMOmPPbDaypgMWAe&XQ@o#i_g}qq$Gqbh@G;su;Y`X^vdn|o&~(x?wn)3!B1fgy#^$dh5g6i<>3V#4z}QWUSAyj8yvXydtsqIACT>8R(HM5kGnzRUZi>^I=P=$lQsO_=hPt=n zm^7urV%8-a&zUw>)ML1w$DM9-!4{fzbP zYbXy^WxARyJ#x;c{*`wrptb|0Uqy_PBu)`?mleIxMEle5t4)?WReY=R9g_Q1vyFiCx($PG+Mj@Ha_#M?s)r?#Bh<^+Qo*ypB$tku#-p9Xtt`T|~=L@fZ zJ_kX|HMVe0^k8U91a?}Ez3kJ=D*|jf`Mxe*v(+sTzzGlUcQJ0JsD=6LZZ`PJx#raK z^+apf)MWefTJ?24TrTcMljyVBtfYn9Mdjb?i}rZV+jDjt0Qr%eMSF;(8=TEC1rM+_ zv}@$!*~E8N3g!liTBxGBu&HwQW-=Gu&j?z#BV7BM*6b!8&MDO{<-GicRAQo;l*zo;Yhgg}#mkqxAA@x0M<{cqi|^0tB5heg zKHGhi;ylt(7Y-Ao+8v2Q&w@@q4^mTiR(pmM-pia$u5??D)nMC4ZEB~7(K>Xul)kw1)ZoI7Jdta0-bDLYST1~h@PPezLlVcxM z4%RxFpafN?UUJv;3~@1^54@ijTO962f|Z7FvtH`aEb)YUMV_-r1-9QF##Nz|V1@4{ zE{_)`cWKxs@XV=;sSWhgFNB@tI|wT*kXP=n3)u8t-ZyTu`-_{tmR@&Tk6*vc&#%d5 z)&33?ILNk92~NNheIg@-L?K!W`rK2AW$vV9%-CuRKej;v|J{$Z&z_|AYi`^vdn4u` zePt#Br7XCr43dvc>(6zoO|CUGsg1)-IA=Ac$!>!#DC3(`7`a=wQnt}ea8NQ~o_(K! z>Fd|8-no~=7vzXBwWMol*uEMxmlU}atyPjfyNh#FP zfGJL7D^m?vB2D`7ssd>dKJBS39zw5u*8OQ`IHHUBHQ=xDJ={u%n*mC>pOQ?g^c_Ul8qrx`IGLt1m=8i@Td46N)NHt=xqzz zj4D1sXOaabuisPe!EH(|cqC*K3oNvjq z@OnL!Gu#o*Bk#b8r&i6jyQ%svH$;^6(e}%JeZhtKGDu98LRDV&EZesU8~iut&QRT~ zw3*o)ev>c39#^hj&_WzUED0%)y!5?4LDWN@iI^?Wrh=MOy6oPQHJ0W`jyM-|2u%>O z;Z+kqMw*imTMW7rQAvqcS^&y}%65Vi5M>U`m$ItDuy81xeAd2A-S4Bq2o?2wpWZLJ z0sah5jwMYpY8~XSWNIh^Z=xb@He67@$mS{knzRF&J-1ZV(0h}K$Kb+F%-KKxVlna( zY}2oTOrI?aJsCcNI+EUwvcr?{#cm0BTCInA{X~V|LT9J|oAg!%pS-1N_m%qO?4pa* z!L#)p-a1owQI=$Rckr{dWi8(z(jCl6h7>8GTZU4QUW|{8z1;F&alK(f`tPHj4d#Px zak0CyDio97Gi)sQlsWjUXL!|K@S?VCVftl{rm9FW;%{{`?8l^2mvGhkUsFcskW+dn zXL+ks&oUSXuUps1UPCJ z!tMNjzeBLj*wQnO`|9#PIJP0qo7iJou|J~4`_WMP*Zyf4He;eL1VFnJpN9Uu5 zp1L(s84rCt{Y%xq5eWRYcVw+X(%n2Pi(Zn-b_JOMK|2f`9i+iJttvmvesW&; za_<{`HS3v5EPTDdKeumRR`NzO4E?4~lCBbayB79v*qcsJ{1T0!M`Kk}AC`typy!Xk z+r@J_{ZN^co558(Wm|ez_`Tjcv{fpp+=JE}p%$&E0&Ck>Z#H%KE~ZXF92O#5nDRXn z8VhrYLvq`dU+K{*dVcZv4bgmqKt7`CxRKh$r?7yc@eRE&DFz0n2af8!b5~t12jV)G zt6feFX!L(7iX&q1^opOH&iMH9wd1TzmyG9{OE%S8{jmc5pl{gZ2@@J?=q;#69q43V zq%O%(s%-!5+30n?mb@PN_4;JlcxPFMVHA(*_*XyY zvg$|XW#l)L+sP`%hpBBY4RzD=d&LEhjZQdLKIfrxXr3gr(CxmmD%*Fr`%1~n=&?Vo z;f~p${~Y2SRdK>~LiOx#=twLThWbZa;!&k!=-;(HfPP^Qog7h>eZq8&(YMy>CVtdH zhIQ1Sy-iHsSB@QTr{>HaLF_JB*ivuG4U4$&FN~^XNeXNv@A00nTTzM6M)FWd@PVX4 zEWt1Wzu*MtmN{#ikJ+HF{dmfP+1@2Z9oWa$q{j56H(9##EY06W7tuBiLO|s88OEt0 z!uds8!a(d>(UPfXJ#YQ7$ViIU8XRv{xcrOxa->e`pFhsrLWt;}D>7|bznikcx07ps zJH``ImLKh7{7ADdnZy6bGvh`c`h`gLhgV$lhtRw3&a4?4GBWb6cR5xECR(4X9^OsAJkQ zTOLMs&{%5*+G>_w)=G&VQ8mA-A9zwiL(k);xRp9W*Vn~@WMhkPL{5denBcl}D50h= zeLcq%H~w{oX2rPnxl7qZ2Wz{R=df!B$ClD_$DC9q=~H7e^WS*gO+HWw8Q^HBK-ESF zH|Vr$JB8HmxcMpcsTaz@7Z=5^MVxE>7 z*=Lc?#L=rr%Zv$+LGHAOI&7mYCvo%+{ZMaVjxo>HlX$GU;lYe*1D)pn1`28{%YH`nVFd z*`{>Gn2JH`)J?vxtX`D7ytAU;EDX0E)36r{>npsEdjFB+hWZ0~Pxi3(F+FXMTV2(- zRs}rAK=;G_dSXL7PywV@gLJ>YuGf7Qj(~ojZnPj$#~9CvPJX-T-0H7f);Wsh*K4&OdZ~-O*`v$MZ5hSZepv?TjcnF`*p@XLHW?+XX*&+o0Z$i zJ8_;RMv{^#ukcK|pHf`R?veOYG{vSzOinnYytS~jfwCXw=^ghefdn~~o^w_**9eXG zq2mjc+R~(z*K$y_#T&UdB8U@I`B>tZBmU8eQN>aX(E1l7Rn9;@y(csji8ga>eRWEe2H=mh)Hw* zG6(PU29kAJDxBh@>b3Lwd~KWE23KWU%#KzjdsEKVzGU(vrFc(NsD-P6wTDh{KDkBJIL%EWn) z2Nr7<-Kl?KTKyioOKo#?#>M`@z+^RgEnDk2K7C-0rbJ4VKa-1I>NcWOOfFGnjc@K! z@E|i`8>rX3dgio5I|H@|Utr(eU`27tCI2-Vgvexqkn`q!nA}hz`n8DrnbKm??8c@7 zQvG{5W?jo+)GM;*sBoLAjhL1`dcqYY1FxMT=)QrpSrKDFjWd-rC#9se&YhY{#%ZsCongmGk-?hNn;5JAVGTI ze!R%$FKuqiATLnYg;+qO-$iy;@aiumviVJZ+c?KxOtW?YN?}E8y&{593Ymz^9fN7O zRU{=%!;2D77B2b|cja#}+bDNuUv6IB#A zsVdEow-So4YKluI@bQD1$4NKc%UV_Y_tAUDm0u z-0sESe9k4c&gZ{yI>)c!H{J|LN|2&6sAHOAxe1%YxaNTJe7i7WP5jQ=e&kU zeX{jrfJKj$4@{Z@d!h-FuXCCKUOi|QG^cv4S^O5o^%f?kr#|l|Dg?A~PVdBA z>(eZ3DTO7-rhGjgPXUpd?wVs5|C$)T3}BJ8<8Oyl#jY{*6Uc>iW}TNabao`r*&iKP(=@5%1}o^2X|G z{Xjcqc29PV@7G6J@DLSQfyD-|w-bh5h1|Hv+Ujbio2IMEguEj&_IL1oxp>eo2<2%# zJaXg$Cdu%lJQ->BwBGq663lFfsoqjFx%^=huX$O@>hUuR^E>$Z6C6eaO5!Og-FHAq z)udLh(ApqHZ*H>t8!5-VY^b41^x5eOnwxwtKiune8P4pFiKv~|TdwWKp7*_b%QZ8xJXUk$n)^G)#rN=+q zQF5?m*UyV})Kf!Ti_d2DEBO_3$qLkI63Y+1#(24SPUGFXH>aPD z3oG9t$<|VrvoVfO!Cc*}CitkxGP_yr_q*t6l7!|y6o>-o-$(Le{VfiyABjm~s{1O@ zw*t|{4Z};Eh!xDIhDw=#S%1*I0vB34XHuuV#}8bP9*-sHdoGIoQ_Aap22^4y)2?{Hn_2Y6s_r zygs)NdMvytn|kA>xMaV1|31MfENooDX>KgJTG;4o3L1|$+4WyoflnX&@$-)lfAkTV6GQ5E{opk6JDk_~_(ZnMg>Z*ntv$7Y|&yY2npBvU%qLl8EIFs0Z3HR3* zp`;gCC?OHSLXJNkBPR8By%**Kk>ZI~vgZTuIfvhe4%JJ3T^o82i7%{xCvWoH_;sLC3*<8Ek;y(rmHjm{oe<}XcL_pK?F>1 zLjFzB{r8jn&*Mh9Z_xfR$b5|6xLMC1+gV7hct)LAN!=M=InnJ4j~9rK&!l-vqO_38 z{j@v0aIK?!Vk0&8mo@H>WGR=V#o+{h`@FfES~Kc%C8G1K&8o$1RD0rF1dT@?Yy9?l zJ<0`VRdy%vds@|_4`?#jv%t7@PxlIp5&r`1d2hU+RD2Hu$3!URo%!f}G@qwHsDlx30Kv;68k%Rc+93 zMIk+}@!3$-$Jgn$Re>fd7pgnL+xm0qyGXn8rV?d%mv>f%J{Ni|?x2=cV}&YMt@+I&Snd0^Z01xzMz zHHJZ6SKC)Ej~doASJJnu_s-?`Vdy|@L^*8s6lRbf0ycb3+0UD$$ryvYf9x_j<>erH zcJr>|NY1nBJ1UvEKeSX6O4CmA2;`eVl%ftaWR@dga%OPH) z&6A{6GJnc*Gz9W!=!T?MEoU&E*w7P+5`w54pK>mPy_MJf?>{Gn6ZBVCYj;%C&h*Pw zzlIk9R`46WW2a#8B~t-4yJs%{U=AsgWc5^I22lWtgS#nS2QYVVY$7_molu($zHAXv z)Zzvx_947qcnz>IAALtMyuO~=6D{pzv1)o55hEawdINBt%W#i;e&6GAN0bc3(sP)$ z2THg^AVfES)qcl=e3p|mIbN12wUPB0!Tx|Iuyl;o!A=*aDHV{VkXUg@H9AiC#7ZVd z1)ixklQjr8e1`Dnw@MW<&%|t}l-7uS3ztmo6}S5MI*C<`{p4s29m#dD>iU!qL7Lfe zE@H#sVtc_Dsw+Dai=R99R-2w&AXR!9m~M}pOj-HbI{WC4)y3>tWanu5BL{Lm*y%v0 z*ms}QCf|9MyUq+KB%&f_qONXsR@Nz$>}>ZazjLP-HkjFhx42b zXr8U~`%@yHpJKJv$5!a^F4v;amiO4|*+^Z9Vx~aeXQV*b2JGav+RCDR^t>pP=Y%KF zfk@j6a}hGU^@6l92$4sqj|?x%AKX+Ea);Bze=Cy74n8J|(o~@3D4qwL4vIY;AEjng zpXE=%0yFG71$-J^xd$>GqC9Qk40aT~%rLzMe%NQ{yZqEDQ3;;utU*-j*lP8-u%=u- z0g66OnBaM}ylbwq*(Fg_o2|Bk`Y)fT{wiL;#0EM^4RG@8r?66$b@_+PDwa+-jM@R* z_cZ&Rc_uk5I^8|)WOJM#&^%srjfTg%ddP|K;;+!@&+u9@Gn`=KgvWO2YYXW#ME@3W z`&$=MkSOi6=v2IQOxqBqiJlr!ogY*aJu#SLEEo)#7XSPh>FAU_u-G~DX9kr$qHXVm zY*a?X21^|qR$XpiHF?--M`6};GBs<;SMBSVJV{RMQHvaC9>kprffUhhr6%0?VxL>J zjQX`Q$AucMqtnmx65yC+@F$>opEbC4VvD#d#?T1Da`og|!K|NS|0+D=u!7<)r2e?uo&cffkFmU3huo^28DmLb|?WcM_c#Yzin#q2Yl` zC&d9Hoqk4)UOMB6!P>|PAx_n0JQt6jrKPk)sX9-Is?15o-~^1}>G0sBzx&QP6xSlZ(J1~CQN^V8qV07eT}d_`cC2# zug;&Bk6V)kAMkOueE3j)b#>LEBMEBJrJ;4F7S>m@?tc3i+YoBgLvbVTw|Qny{6%yv zLM)D~r`Gi8@gtK+5{3Si*J=2|eMHrRd*%ccuywIbQ&c^elwMic`kzquU^Hr?Ymd?y zW&2JL1GkW!PTw+0is|?!A4|vp2BKC$_?=vg0k}XFSJ_USEVd8>IF0A8`H!FMDXjT( zxKVxgRPG$#K3xZ}wp3-p3s3Mrp}7{gz>q-M<23#Q8VvYU=v@l_$u(C1)^^rWKfyq_ zj=!@4$u8B=7L*Z>w{5>Vw>ZRGwJZus8q3Wb{GTN2_=dH(cMl&Q zAC;CI+zd|;aeE{*;!BLU^x(}a{vp>f{gTygJ(sn6g0u$0TJvIfHOB?E+$PL9 zUoz~C>Z#dv!ps`&^`#0lP`l{&f%WOl7`l!;TS-{2WR3?}J{AiDWt%kxd)rgua0UKv zDX<`Xz-`k@BM7wjdc`)57pm=z*V;E$!|eU^#YhHg(VZ0}lE!216@mEnkHVd`ez;1q zGz^Evm2SQQU7hZN9zq4M=a}#C^&ik!?aUSV=un%g)$WxhC2wx8?J-(ghlO09omq~= zvAv!n2`j+_-9Uf;tB8c@ti~t0pbh^_?;Q+G$#ayrY?pF)Lplyhsp9tSUK9+ZGNl?g ze}hf9yr$j$j#K7^Y9J7v3l&?AX%823XYR<6h`JCpngNpix>m+$_pa}qvB)Lg+idqi zAbd{wU7$_aQyui#+i?r{2+}B#Vq0@zd)!i`E1!s!QdWD6#P{x5p`#COs6-LA_flBm zxMZU1=!;ESvC+MTQ74e(15XPiQdqpeaKtD{j9Bd=%kn}$KAd(y7PJYm*M!iB3hj9l zo#ub{5cFEHh|th%>R)7xj05`CJIs_WHBgE)dr@8K)yU@Dz1D|@?x>zc%m&2T*cO3Kwdtv8I(bYH9|N7j=Yy%8oy4$*k6 zeC55@9KHhM^kPL1yG_L-L5s`8^@izGo^}zQ_FcEF{^5i@VL>do>IHmgnQ`ZOHwr}zU?ls;mCbredfa&>wT5^^YBj4xpUVa>Yxm94p;T`bOstIIlw zue))NgIaCE)Y0+JUhVhBH!wAOTQwr8tbL#*M-c0MjOS{mQR^yKRnBU82;diuKF{UW z-s7WLfM8Wg)s{T{7sr>5#R$k*?&$M(yy0i#7FYL^CV=jcT8KYJHJ% zueRU*5+OC)OCpuIPPC>50UJ^x7du@enzgEzB6z{q>$bTPYKd#o8p1{x!UI;;2GQOw z36BT^;WicX#jsqr0}nX<3SrHM`WnJwNZtn*3+mMF)#4+iKuz@A|M4fa2gy|6wB5?R zzHGd>h#WIjmKM1Ik-aKfuuwibxu+Ox$6A}}N~f9r3BkSCLG}Z%a2l}+Dy^FtW8c|lWs^wmfz;^qm2d6d{59Yr_{wv|vhH?iA7~GQ8+5y{YrFN= znt`xhF2^w#Dc3)JDBMJ`iw7RHRBEbz>G*axOaXC*Tt9RH&^j_Ogpb;cdW>apyhN3- z3z5_%EgxvLGu*Ox!I;vv(ms=nAFom+sl{JThT2IzKx_8m>{aW6R(@1Un4+aYe2H9$ z&PyVt#oP5jUW(N;lq(QH>eZjRhB#{ey(Vc$ymOz0!HDYLi@`sGSw|0Z*NZ{KY1~PX z-vKdlDtCW?dItn(50XH>D7Mle$-ee}Rn5w*%JdnKZ4g>W(Sk&lB+>bV&!a;V&7fE{ zmOyAaX*-J5Z-a*-1}yp9qeU(0wTz zbcyFmuD#vH2aw zLc3B}_Hu#BDEazdOXLo>$M77ia;u!nr{4uG*_$Rp zt3FD56H+mkPa-++Opb{ZePB*V2tuPZX`fzw_h~MEajXIE&@L*V^dQiVRaWFLtD-K= z79NjB&uFoSZXVgqu97$c{=6-g1tMFfB#1bUS06s>%7O+#cao)pEZ1ih6cjdJ1>`+< zVKsIKoPhA7wCPRtqGBfFR{LosNIW?IDHb~RIjE&(+i9&VKIFhcNK=4Dj}Y%=Q>l&X zMuEi7NgM-?oeP?a!)@z>E=GOEPw`b>Y6fsyAX0dpW;(Zd%eouh4_0BjuP+!xoTm|X z_WU;HoN1T-kaO<1m5WPwo1IZVKch(8^`rsS!a=96Ya?WI!q6ooglzI0cZ&$=-VXp% zXd-o4>V)}pYUH)}>HkjflSEaKTXF0g^_L3Ba=sIJ#-FqSi#}M^d6ew-vi1W9P}h3n zu_7ud?4%W~uJoa>bmp7T!R`6i!6r=t&xy|`&?)rz*vk8E=;}l2m=h0{!O6we)C-;P z71H*dUH9T(`Quh}nj09ab=Z{p1b3(_0nbTPPv**T4(Y4}V@=xT5uC77cn73qrLmpi3fbZJ0Us&e9x8=XL z<$q0xb!1L@q#emH=*^_OJg(Ll9_H3W@ftM|kn|o060<{RW_R=q;g5y!4y4d~1Q1v3 zK|?PNZXdMmVzi*c{aEgMvNMAfE};9IgZIu02Z(;@wIC`%Zv0E!DFx*-B1hs;k$n2i zaE?%wp5l=fFei)Vv(hAp)Rb-{K7|CIAXa;68W45!P!*&}of<2&TFjXtKA1i9jOjW3 zm)aCurk`XliIOlz`Vmma0!O;T0=YQges~>#g#!X9dIOsWQ4y#j(Q{S{qM1J_cvz75@B=nb#}W*+%cxzc=*ip=43(``VoE_kl%3m;4eyymMz)Fz5o)2NXnn$9n* zo);xB%mr8-SW-a46R7C2L(F&-{l4>tV!h!x}!Ta(?kOxPOODN5DxEeMC zS*PhK?$))Muw%{9Ia->d3wX(;=4npi!ArM^5TDXuAhuH_ha(5m)6g}qHGcegj);$hL}1nxG5Mq+ZRiF)=uSE>Lh+P|Y3 zE+9JP)FV7qe#k{6Z{iLr9-LW=SYqyWjHU%z4CkQy3C_@IG_R zu?&3kW8#O^ek6b~bZCxG`j0F6?gf^8ho%v`+J{&#2IH#RDS!OGV=sC=cHa0|zXMvYBN+{C9riTAUX`UuN303Wl3&ii!XG6j-syRu))Y zbj1%Bd6jTP=_>9nLXHy#zPwR&FZreECsl0CywHCR?hd%z363SJ5eHn}h{Y)VvN1Vu z@=MHeqGtxJ7a2{tjh_4nMFfVJBMJVCx&Y}yeF_8&k2 zU%4U&&efB63knRT$n0|SU@ssn3$;p@+g*?FP3Qt$N2aiT$`OORr%JFY z>sGqj6X?0imXhqmgGh8nZf<+7pP%19azjohS=!z(0+bzhx{7}e0yDp6;rJ>Zs8 zSn-_S6RZBgaiGrFrr`*1OW4lJ?Gqcd`n=Xyhbi@(^aj~{t^5&*vmTyejM7}Aw(~yN zG~Ib1O@e)yxR|n3|3JpyG4oZGNv(>=%Bt^-M;BWi2<0Mr<8f8%0hy`;Y7gor723JT z2z{;b*`tC;;i_3NVMspe)Oha*br$LJPAfO?9U^$;;ouzQ1_{U|e{z_6j)aWN_fLhT zxJDoVuj!!u6+W$(1@C-?P$>welA}CW(&Gq~QnoQC~#%Nh& zRpe?B=nyqwXR*Dpn68v4)?(Rby%r&TRccsBl|g&P9JlM$n8m@2xP;nfI#XCt(T3g96zeELRo90gR!}(g*|#~nAB(b)*HHht{s|i z6(BE7E=I#Y&rO1y^f{3rR{-nHRM0lL#&kv>e3wM|T)!+@nr+orI5*_y*hyQ!2P+>I zb*Ml1X9Mo7=!i3<=Vc$=uktu>EER)XJ#q&ZzYsV4NlY3`kd5Uxori@4F}k)g zafm5|bEV7+OmKMj4dvNcbK45_9*i)xp#Kqu1a1Y`8G%a^-=U-0!lZo8DRQ=@`fp&j zgC2?@C_kbQq&e31TQ z1_lcjv^b9Z0@WT2HcCyRad2Y)evx`#tA4q|e#mnFJOcN~S8hHj?F0r*I2{cJGgH(( zx#mIuoLb^Yksh$vKVI%*i3TtjwFBZeYu=ZA!Ymmlw<)xbs7Hrso?P=hK-ceb%GrFJz@4-JUzsag09euOKypr-^-yAFMfrU+VyU_` z^~`y)aIbprBOTNckL~UR4|K{t+%1&Q9H6rg65Q^8b_GZqVrP9g(eKYouf@^TTML5Y zFCtJt0J5k7nX@#N>osp>F;wa1=Ak1Fg7Kxi?km#+RNa{dni)b&UNK5vJH`;SDq%SB)eKU(jU&DThM)?0KZS^*JIHkV3Or$fdH?&up1luiJ#tmE9U{ zTjOC$HVy{1=1ETunYrW4z5@D@T6+0Ve&tKZy99of;W9-j`C!!gytn2Z8Vffk57}L#>-m)5;LHA-5q#>yCvoWj#y}k&+c+!iN2(T*-U3T zOyMwS{0G#A(YO_6o|C4!t0%-~SWC+Znmw z)A$xiVU_h2Gt1Er;Mt~r03=zaTiK2+C+>NQ4Qc9GN4PYsgCO`i41g{CA^N&tU&yWD zy>lNRw0E&4Z5E@oS*NB%-Ikvf;@vk*rkoO6_^haW8ug6)lVifP@MG z-dwVoaN+0@qcGg4QItKb9RLS`b`};Q ziH8O+1Vqkf5G4)uhs&J6HkH+Vx$(j&09Xf+pwF6me;i~%x zq+#C|^!kv8Z67#b#6Cn^2a85@mwTn#%a;W{s{jtn42jzJeLSp^J%^DD-v{d=wPzWz~^PFw$<`&gloJ>Q9t&HV44^B9^G>Nu z3kU9a*H8){aQ+E28Q=d#GuXD1k~W z|ETcj#Q}vR+@QFQih>j2&Xn>o+)Mx=ce7rTk|0SAHr4ItYM=@;-AQJFJ!X|AtG}HJ z`nxK52mZk#>njDOGRFX^7@H_h?j$f^C)sCPvxCSk8H(N4c8S-?8DD#E)X}CAD_*Cs zcPwLpg|bUut7n0MJPppC2CVM|_gkC$Vf>p))`~Vfc#y&u0Ov2OeoGq+2>5-6hZ1 zRbJ1dr(!4q{&feeRJLYo5RFh%5{*y+}gT8FSJeQpOa} zz$&ta%o?Q8R2R^&TpFf}Q_p z2ZyJz&n@a?014qo94W_tjI^Zve6&AbTAnnKngMe+OY0sH>YqWwfh8INRXO1{(<$o! zAm-cc^C!pR24itw%Q$l0{#h6si1e{hS{zTkC!|x}PpvyE&3DM^|G4N9_kc*c$H?)| zdX84u3~od7hqM!r5@8xp2pJDk&YT?U5*X{!UtRyK=V;UjU_3+w6&}gKqbYC+S%9(2 zb~-usACvj$GUfw9=D#94Io3U31>ZAPKY?5Q_fYi;+&h3G|L(rPgm#QsncN!(Laxr6@X&o zbE1wr#)@>xV_+?(L#&*ZO;=7 z)R7E$P872?D{|Z#19%JorYENk@~i(@*dI`ueNXvoiP6-FBV-5BLR~KL;S(IRVh)%t zq0lsrz3-2mF392Jtj7pA#lH2@ywhOq?A~X+y6(8)fs^Z^u4~)z+16aVbiKpz zlQeTm(b=qJKQFc;X0m-Iky|oK7kp%=PQSpan(=_gYxXC@K*C-SDj~{NE-;R)sI%%p zYe-7^@)dX{0>{=`LrpwdHjUEZlrQkL=Y^B5lwcxW700Sqe3=$ywZK zE$Z2@l29b}dQzZGZtT7&Qk9mnZYwL&*}yAtW&Dc_;=DtGZ9(qJ$lN?cF>{qt2UGfG zorhKoqVR^tImUYK5R-F{1n2Q!(6;IT10_AfV6L6Km&QL&#s`rPn^L?z>@gS4YxVUD z|Calbze$x=Yw{Ca%F1i&n~us{0cme@K&9he;2)N^6HQR#*=<%9{F6n@$cQmWQzGMr zpyN}{!Z|(nv6t39`HmX9p5yUbC7raDLth0u%J0{r9}ULz@9?hX%*L0DZL1LIt~ai{ zEfRlKLaAnk`7D{Jbe@uYynV+V|27Y~qEZcI#khW=M?WiT&hlsS-SGY_0lTrny*?aR zHU7@h1MwrmGl65gQ+tT!hn|_4nOWK*=Amgu?@(Z-P@2g&Hlb~OyAMzs9%2cx0eh@+ z*bukL%EBajZ_IYTq5{`Nl(l5B>@sqQLv9vEcxF$ ztdV0pG*{phN9zAWJQjx2n_E5o03;Dy=gD~1cTd&5J9m_XHg-#2| z8x2o3paSg4r~b&8FqX6abB^!&e9x0mzY81+pE@YiA}i-@6MWvz9UC``UXC|$++IG)|ATW%4D#!or|Pa z+Z%dhphs$Tj#^cIN4IJ(w%$H=$z}Aq64_K>{(3B}EKbf=jH4S@_H0e}raH|fl35Z_ z{+->GWM;*7>rokB<~=?P(n2B^>UQ_5LqWoAa#1(M*a}x?8{(1HDFIQwAP81WbT_~C z|6uN`!=l>Sw~rnb6ahg(kPcypp#-E6q`MoG?(P)DAOy*wkr)~Vh91gbq@=s08ERx0 zI_BHH?>XoF{a(-c{`{`*FXrNcJ$vo7_IjS@e(w8T^U+A%>YTzi7Ol;z_uOok?{0;G zUBs=UQ(&ftv&1I#Gc#{PC8f@q9_I5-hK)XU`0^5a9mU*{NnC{dRWrgsc z*czVWnai}))lX`y$IWkNaG$ySxlt+u;WQz_@87{309Kh#E7FcMG6lfx3Lo|thu*Bc ze;_|sJ{Fc$yTc(?#N!ewe|ouW(d$H*1wT0QoWZkb;v}@c2XGX;x3EaH_V_k$G-Fff zQ`lpNM5f?K2Wyh|9n{i%7rQtY?1DqjY$R%Gf^LA>Ep}%6zT6ptMrLemtVrwkakWmj zP+OAM!MXOrjCgE(h)tdQbQ$JZI8Tx)@#Jy(7LVz`WA&4Cy1>;1Ad9Bo#6JjIFL#+cDAkWbmY~ z$Y6lSe8Fto*lC-`(DpqWa@N8UY$;<`rm5dRYD{Xrb)bB> zIjy3d9L;vQv)w6k&9_Lw)vmfRTux?|y2*d`?d^fU>{#*ak09T5mCteYoR-HepCnq& zLSPX?rn6%Cc=H~JOsAxt`tUHtmrus-$)4gFcND`)yaBrJ*=S`M+AOB0L_=7u>4Aoi zlf)c%TVtbxmP!>_4zskV_e-m2Ezz>h&WCyEbUA;)W>&)}#Ef|hBQ5-L2qZsK3&sWR z;fy6?(++fvb!mdI9}m3dn31FPv<5S+hTdnj*tqVn?py<|JTs2_#8dokU*DGal^^bE z`*?&zkEH)T?r?Ih@0L_p+FI`}9~gZ4GN40iRPHU=qIQgW)N@xrEpL+4Y=K~H?~KFG zTJkwOgsd=Z4BKTCRUtDEE6F}mT8v=}QMei*jA5kM692U(hn^#`n^?{OajInu@S-2drx77BJZG{Xdm zt!L+}+b&jXOK32`y+v93wFj%5TJc?FAAj^SZCRPvmV-g1DD#tC(>%>o_NP=TF7Ari zf`jW=A4M@RU(JE4h`)02Us%&pfQF1vwCDm|1Cj`&eGWU{5=Y^VOZ%oPh@v-kqIcgy zwcUU1yv5$v0dQGF+80ArR2Rzhsq|y+MBU+1PVMxr$6s+x_0}U=7otam0Ef777Z&xI ziL<>?s(`V|yH^akRallTsG&Og2D&v4&kj-vFvXSH3nmS5JE_z6ba0lA%U8DO+OWGR z10NKAuLn5wY)sZRAh?97N*^q_S!)2v9Xq5mnc z!n$=n=Bbq~NO1wP7=CxE?gVs0C3h_U+ z8J2r_JCh`Jc*6`+&uc9?=9dcBydXpr`H++bELa{-?zwK|ZSZOR_k++5Y8}1=&haRO z>k>IgUZ4Uv#cl|9uiFP#8&)TxTCPW~b1lEcsw3NB?S(@)_gKn{zr?t2DzHK$>Cmq>Z0@*=Homi3SYA_0?JHSJFyQE}SLD>+iC4Lb# z=!80WuH0#lmdGYMs`iOvzgp6StVOg#z33z)-&lKOroI-cPnD-+rMLti*iE08AOm%9 zW47t0L7nr#8}$JdC5MM{&wb3xUcn)*cXPE+4nEcBS0V$H%*ga23^MVk?IH)KboNe^ zH*Dv%QeP<4O58-;hi6>n6g9G-o^y5-2KA3Jy=KqH#Hp;B7JYp{1y<#3#-tg2P^=6K znK-pKh8jLRhueiEDX2+kMi^=I`?G{R-HBWOt$ef+TiZU~3IFrWGX}F;{}~o-WONjTlG3gjm8)& zkZg2Zov+r{K{Gv>w(BEa_o_D+X6J~VJ?=#&cKi0`C(pNS?l!4$VQ5$525@jgHq@y1 zaLR(xky^6^a%5=cZj<{!LSB0fiU(8Y{f@2;p;lFb+EXCXY+(4_;{$2RdT7Z*{E*;_fwc?1G48^lR`D?9UL#Aas%jnQE9IdF*^?AbLUNHq z0tPY7k3#&hxen_jL8}PEpbd-%q_ESRSc}O%YIt-sbwNccPg34c?qsz_iv2|%3G!i$ z8isSza;|WnUP@5N>m#@0`ag?tn(o+S+kUD8z zSYgIqUBn`b^JFonx*j}vE&7J)S;8W2oqlTnyu8zU@rUl58(^b$fZg8KArW~ z6wGf#wF~>RGSx$V6l3FkB(n}VfM-_J4m_gfC=yL*ko#Wc1jV9;PKKn=sNjlVQrpRo z>HtD$YJKB+I(mTMHLm`i3k9QPiD}E04>A$usty5K_R2QckA%YzAt?bu=X*)&jp#(A zeW}q;t@^*7LpT`h-d#BX8zcwLlx*8RdS}X^V)X}=a8N58Uq3~UsjEcSaxS;Y%Z{gJ zDk?%5`g^B+hLTqg&Xa5hQ%5$TQ__K7dXGepV^5^8NJ6h%hfKqYGg%2aGG$4!f66qQ z_9)1i?mER8*ncU;l5tnUvjzvcS}$y})E%_v2s>XN!yA@BZovGN%>kQ1alPHQ?=-py zUMb9>zh1JK3G87~2B5xsm)qYuhnJBrb}Ce`sE#11GzIOODaO5%|3)t)Og?r&vqNwP z|7M+*>xR3z;r7MTQJD%Fh9wh=D}SO>#*~0*!Z^C>@?Yp!I30&O=640`VD{FZ0N)4S zYnx6*oWHU}8364);ITpBC;1C{NC*(395-w?|4fws!e2hr0Izu#_ipenun;vV0EP|r zjgtRzvH#8A{~th);7_`JZbr$kZa4h^`s7pJxc>{{=cot(d$Phh27f{Vf89scPguy= zWBnIgarFHkJ>9XK+?RM}P?~4s?;dDmXZA}Ri8(A4C{>iX{5Rexq5Hw0?kwcs?mN__ z{^Ag$$wX0~0j#&E)hk$sS|>vK_p{nCa)XN^zCMduYl~}g8tt=5Z9!*C-XAGkysAHi z=$!trRoM(Zd1{65an?B<_5JBowYD$uunD9VTH(oCw-RG!w{)^oOEofLfeTdoS3jQ-kA4YVQm<*$;HVx!{=yI4;XhG^Z`=`cwf0`)B zW(kfPO0*s?jXw0=cn?U}L%G&5(d=nxcOF3>osYL|0Sf$iaht?Y~g+VG7< zGT6AyOF|*Q&ks-=@o<~gveWt=lb~ejPoJJnUZHoHoBeY)`g2(W6!20y@GG}#Qk20} zj2hw5Re+r+e!P%rolEh4XD9VY%!v!SYn*v&Sop}1D1(ChW$fj?rB2|CBa$yjFiiMG zfh2NwzE2GU3A@nrV)q$LIY14>3F9e|C?@yt(AlegITZ{uo-|zG{tRuL#t#J_?-7q& zqH#}+TkJiE(ugir*oIHHU>2Lkp|}MC9_10cZ}vKVgOBkFdFakwnKm>w-n9A}tF#qk z&UUafBkt_1MZy3G)j8Yqv;a~(VkJRk*(_e}20Kjg$MdL%x~ zXq3Os)pBUJfmj$%IcL5SA0j!$d2ycKhv&*3OAcc%0!}wN3bB2YEI$~`$aySKSaq?V zBV5<=Q$RIt7;+#?Q>THRM<&%f1Q^eh8`TVxDA1%?Ruuk};Y^4uocfCHb?_90UYKjl zMKRyL_lP%SYi7L=@V9iM7IrnA4nnsM&j$2?%&uwu5(1t=Svl28Kx$dE;o4?_4(iHx z?b`NiA5t(UZ$@2FwrKM3INfW%KO&D*EIJPM;u`}iZ|7)6C^6pFEft=q#XG`QysJN7p6qo*uP(&D?`}uea~2I*}hhwJj`iEOkfgCe8(S>SroZW2lk+ zN>E}(Tzd~kSxS1~fA8RdRUeh<%DpAG0qpT~RNqCHctTMg zeL)EHz)NCLK;^@`M@VbW@!WPGE%631U8e86&ARu&SQxiy#&E3IPU__ay4mZj+NyI^ zXvU@4rS}L8aE7qkH3O>y&14JF4*n2}%VrvDxz&Zs!-mo3dxUx%`BBK$qse76Xxx7r z*@e?FRSkcEdiD!Mv3-#Ens8`dvRgHJ)U$l zJ{~t!6TSFMj;gJP!=blsT)F)i$rC-eF;xrjz=}*StUN7nVB- z!g3SY$@ubeRGD=$yXLTA!+c*FH(o3rm zc=x2M>_s&4!D`XRJ2MnTQ#;}j<+V3-VoalW*$ZKF0@Zvwx~kzpKfMN@#@ncZDNg5e zk4?eUq6fJ2qL~Bk8*Hs;xEu-v$-uA|PPR4QyD3=ZuQ}a>JXuEh%;j>WN=d1uV`Z8l zftwCM1kDb{5T2O>?k%R28X@-|xl2b4Df!I>7)%G(^bLDhhzs$251DakfL4-pxx3zzeb!#G{Sa=-cP7TNzhN% z21^QAKHV=adW1V)5(Kh>+Qxf#1Ox5Os0CS|`NGa!BkPt}9Y6NFY--91v~#{4nq2Oo zm~M-1Cnh<1U1q91}($HVaGrx3R!~M_G(LZMWEKa$J6Wz3=@@p8DpVzQG^P~JPpF7 zx?ih|tyYfRa~9lJ(%(Ua%o`!lN!MvPZI^7`oVUD!HcUNBa{!rnYk*Q6l^bGQ+O&wt zws_yj(OM4>M7aTdkwfM~rAmc*w~OE_bA|FG*8c&Z<7 z`?Hkg<}_vWkbF_r;Q_0Gk@Q!~c`ZP_)M6Pi^wadHej)VClyZv$z#wkkWh>-_wQx)z z+l)d(DNr_p--H=X-M}=!1~AYp=>kG=OZ>mWH+1r@?V%KdTfd_DFudk-7# zNAVW>oO~9H9{DzrvwK(xu<}*&0h1^+S3M30&Doy;+OdO}Oj*zap*N~>6xtCgP>DWt zNZEXI{d(D25g=dS0qC6S4g(SkS%>};&BK5^c;qPT#}}a@@x8FNgrAN}rVS%vzTd74 zWj1*Y<4OJq$8HM@6tbLV$k(#*RfAEa_*kXw^kGqKi)y|luIA?7-w{$=$Cv=Xicj+D$vmj^JhXu+g+#eqRfNQgGAaky^+?9w{{Ham%&M%eb zonnu0AdEwHa^qEO9R9{Rr}$^V%VI6{-`9RFZ3I+{M$~^ZlN>-L&T(_<58}dK?$-<_ZLP$)+%%tyrT ze^d247#S0M{haYB{u4O>t0*2c{Q3Fb)qnl!mmku``1hKUC}b#H|M5?rGu|NwP}w{g zt1EwhjelR?;imx87~iPz|MqRV*MMMk>)rKV?&E*lW5Fvx$>P9hz4(9oHZ8!D62$S4 z;-5$Mobf%yRgsY>_YaH7oCYas8A7!7LJoyI<}Hmt;{Bk{f02YgJvNv+JD@VDMBhZd z4f|o#eq5jQe#3hY`c{sNiSk=K@}-%Bs*XZ#YzvOFwFMVGe!Vf(3q7CPJB!E#cYp8; zZYq5_G_&bBlC}BL109BU3i6`|ENsSk7CN&OYTw=z@#$jM=`_bG}aGS({#L)PgImF)2ip+d6*6QR#&sGTig5?*2Yz{t$*(_B( zPGGhJi|lO9Ko!$&!R?N~Q?-GwwrAVaG$nwYLb6?$Lu1EzQm zdPSuxJ@ICtS*?olK!!Jw;{gx8IO0lc6;C5Ock4{yKW+fQ?fY)LgUBL;N;o4~qd_;A zybLN6HNI-Z&jlSOR7C#M0;G9>Z!NOr#ru}E>RXmr!-}R1Q)|MIcT$b>*M$U?o3uS< z&?joum}HyI6c#_zDu0lJ_jnWBf11Te@{HcW+n1PC3Eo_lXT#Y|H8G1)%vF+IFd!)2 z9llJ*b73}X)R%Xol-f+t~BEpF-+M7QQ)B9;h0M&PvR3;>rJT3 zFb(Ea;W9IgqWs3=Wl-VQWWc4R`vucIe2}q<(YdeE2WMT0mMRqcTxyaS2$!kI3mq3% zy?sUY;~m~>zx??A<1s^TH*|Z7IM$>HIJQwqzNg1t)OB&GB&?Bs)$)1=@#68LI`JNh zg4AHK?^paP;-Bf%%m4SJB5f>WvT!IGT%-glN{C{zn!GLoVL{-XZKSP zu%w4@8Tm-#W1gn{^ZheP`hLJ4)1tq}5%3zwJr|)@(RZ6?QWEo3jz15uIVj|YTZdps z6?5EP%u{}rya*``7C2eZ)Q|9z^!t2y_SHkCGP81fO^~xU!RNji4e5?atkE7?NV&EdW`&2L z&bXeyrp9MkwA-NgEx~}vhY#f@{5(lQ&0vBuUrUvShq2x>!t2DZR=X`UNil0)oi=3? z$*d!nw_okdB9O^skHQnK|(b6f2D#y1)?_Dj4kB9T8 zgDaejTixq*MRyA{vy=^B+)bnOcYS8FYrA*a=Ng)~=W4{{^ds)Vyz4}BYfr`!9H!&G z%y|g4s+T99*TK)hb}}!-)Qy{!mGw)gZgCp7C2T8B(}=2TX-2%1e@CqZ96)R{T%g47 zqz@<8kFYOM2VoKvxMN8@R~7a2i7I%W0gJlu)=Nc>0v6HqaD~XMduv8*GMXtj!6#42XK<`;Wl@j~EDG{EEs@pXkEiqgR>1mwLme!Ztq76N>N$tk`LzM`MQ%D%V#sD0h=3f({$~rP|N(o_>l*L{qD2=!L0tqO_YvSpC}0 z`47&Xfw?a;HtQrzXg%4KUmoH-o{5aLlb-ZnSjE(~6vJua-cPvC7IWNWBY0__Z59Lwo<9(weU%UG+M8No4DFwL^GQ)f; zd`G#NXENFB!A@6YuVf9amQO7GIYniPImJIIJHn9KIIxUFMFDkD*UNtm zel^@vKEV4AfXE1sXAs7fT{dQ5+S|l9JIQuZ33-7wR`D|kgkAa zPu+9B^tomhtvB||h;N6N%Y08wd*Sw8#SF8%-!0}EM5MrFLtdN$`+2Lh_|B6VYS{~^ zcMz$|N!I*-`z9+!e&mw{llNq|)V}JqsGey%Pr~q3O_^x-lJ} zkL%gFMfht}e@h&0_1ZLwI2Ma6)oh6WxhsOTx_bl*kgq~m7~R^iHlC@-N?&cxl7++V zFXj4s25e<$r7TgOl^M5opLXCp>#r7k(E+*)PiwJS9`|>cen}Y^5`i=w_1kYQzVpeR zr(+GxG}N_QOfEqS9CAInkDk-iNTOH=LfO?2W^{E7`23a30tM@d=$^U!HN*n#f+~c7 zE|*7wIhzd( z`5Rc7>P)2{*vt*T(z3c8w4~piEao=)1AEOn(fMa)9DqxShRTl!4WEB5TOD4%(VH>h z8_AjBSr?o5f>pVb{OGA1hgM!hxp}K`LP7$Oe!TuaWCZSp%s?GPF`xa~&KDwZHdm&y zis|ilF|j@#!6lYR-A)`in`LD4eq>?Z)Y9r~UZYK&J*3vZiFxqIA!j+@{Luj{z3P5F<8P$*ab(^K4nt2#_c4}y10>ayF?p-qOOnk`~6smY{ndX zQmlL9WigZ>u+o-(uh>KmrxS$h{q9j4i(q=r0}(G)#V-QQN*5yo@jDs9Jpyy-kFFUK z`R!itG+(UZ)csK653j2vk#J>4rIfJ*9c{;pwBuM_q7ll6yK~E24V(3-l^!1bwkYOG z$?+;Z0^8;l;Ez(|bS~Z7#joE|TJD#CO7Cg!B6vb=-|IRKK7l)hFy?-3Im(Nn#ljzM z`iEzFT!idScdx|83z(Y2j&|A0DEs5<4d$8D26k2}ZQ_hc`cAB3mPTgAI^|TC7d||G zSpc}=dwwAl?uw!64k(IeA&bd@wg$TncKrG}{d;lKT&?HY{f#c7n^`JR$s+W-XX-&O zF=qX3oXzqk`R+Y>)hxFVnQ^Xcww$>IgK@5OHoGl8{>^u6v?QLW8hVjD=ty52hX*!; zIR#%zB{CUNVXx&0PUS0f{UdAlCK*UJx<_j!lC9lOpkRz8#8gyCwz}mX`zlP8e z+RgMM*KNjD3!L&P;i*!++tdnIc<}UTQ5N(4q?J$9cxkwGn51IQgv6&;tNj)qvs8>5 zdW<9=8wLcR*XSH~YUMaaMa&~1^}ASv4MB3I5qpp?I^i8BM1+%_K4<5!Kn;UFriV6( zvTLws41)qt9injQZWte$*j=fs#(bu~zo%>c)39)PT&&c-X^CNbwN#d6bTWmue~v|I z92&J8toux^&J}gFWV-Q{Zt;ZTrT#DxXNAjsVa3V_@siEcFIyUlyTR8B9-rYFS%VFE zk}JkOuF`I0H{zeV0a=`OsV>L}ZXGF=ymmO}w~%~`oTCdkzGDT@x2p=Y$^A_c^)uCu zB?nNDo;)$L0%tk9EM2n-$Cjtar1w1SVy1k4uembMn{{0$b=yKt7|mSkXB0*romd~b z<;!%2;t?>G`+7Rj37XV;75O>OaF_^J9%<2h`n@`WEA0}JAZ;hcHho8mD&Bbt-fZI( zU4)}jZVNrJ>^3Mc-0%mgS_3d!!su|ZJIXV+>U-=_POWQqu;1yXa9c`(o)cmF7(Itd-@yFsKyNok#o z(ybIOZWEz$0@}`IowFnXvr*_K+pW$efG{ayx3K>p_HMA`f&V$}fpA?Ibj^G!V=1*` zl-3djgGt3NYRv7P>&%_ZsVX3lCUHcxqK#0GFK>t;g!hFylATYnsLwEu<*&n~dYsIV zC7C{^zfIg|2=KS*yXgrGg6_aPhJO$z|L6kan)Z#l4H}DAK!%3>8$od^+`6M8tCG0f z3G1ot5{yioeysGTXZ4WljzhXF+JYAdV|s<`QJptaTvT5W4y~uOrSr9QUWaPIifM&& z;3K8E`sH`T1d=(94WhF8{Yt2+zzSnRRw2j5l>Eg<;&fA0mL)83>k3!q_4i_KpP1kb zRk}R-bV-lrntW*@YsBv;EZ>S%(O1lRWwk2j-}oJ$#%^iVCm;v5H9r?LJ1og-<1j1I zAhqgFq;Y?%5pWk9E;Ha!QdNy1=eE3Ots593DEF;P{cjS$pGB9#&8vGERWz&sX8`;= zPVR1-zk#~=x@9Rn>8l#?FY5Qo-@@i z%@c@}B@fQN+Zp62OtYD=9MEF($+%5GWJkMNUULSUbm&QG$*_$Zi@mN8;^Wa*vhE>g zm@nNPR>2~Kz06!C0Lf9pPD1dkVF-f?>83CUUUfyqw7+6?#SdT#e%Id{!87kQX(sty zz%C6tolG0C8gchc8xNaLtF9}pWWWOd#{%z=PkmuKeQqHEd(Mdo37KfBZUb8-(5vqXHsZeyJafncltFv+%K*+rc#qj1nbzF~v4D;0J zy-(h^jrfe1+s`w;SC>@OoW%ky8;f79DUvfyp!~)raR$BX)T`eb`>rgdh|TC*WAGx_ zuJYPcm8Ziu|HW{ThiZ{gk+IIVh6mVvR@X8nBBa=)Uo2HbbT-gsE zpIxc61Ix-jcI-?+w|ahex=TElY}oxv679~#{PXmSN0IL3Ykkq#^IVY6Lp>{2Dez~x zi6o!sNAgPUGCx@Db-LVgS|s_=5MiTfOQ0{C#_bwudV_ziqOAa)C+VPPgWVY7_uV$M zYpwO&nXb(<`3IQUeH2K)hPAw-?PAZ=TbTFqH{e9gDpO5fMc*=n(N$#-y{^B{9v+ba zK)5%%=0G0*UMm^4JxLB}SpUml{z4cc?o`2$uRc`K{{1Zf8&SbB0jXdh$qc0wb58ZZ zQ>~P5fB)S-!|4|a0HPq8F|i^S`1?%uXFc^p0YLP>;OLA93B&WRhSN;ds9et8Obg|{ zzQ2|dktrf`veum}fb?Kza4u486HgFOSQ8F!syqKc)}NsOzpfFngSVxwx%cA4@++|l z*tGp8R7%r|AJIUfu$)ZMmB?^H>S;3tCGX1-HrsKO=g@AEZX@e%EZm-AYPgJmDquK- z7De_Rvsm(01C}PMH z_BuPEaz?3vRGy56ok!mt&1Nb~bUDqwt?rM<-L*j>)G*sf+7-BgR3e2Sr^Lj#>ChZZ=i4m$|!VkXWzJF#R_9_VZx{v=y zx~u0NXHL(9zGj(fnRHzLprABMYv^j&$_q-V1lnd_m3`{umGK&l_|A5k<=Adq4w7^B zH>k^nBh72;(NU2E3p{q1#grUE@+^FNs#%yU#YoIl%E$64X0-qX57JnJ#AhS4A*@?M zJuk+#MiRH5FQ#71d#bQOmNSFgQlEhRLnVZFj%t zU53rXu0)!4hlJToSGte|$#A}IVRj_n$aVP8Kdo&B7I(?KWMe*2 znYPlKC3I3NH#6bh!l-B7QkxhQCUv}uetTkvWeI2>-lA!`_!5s<)5FD^!$QDuW|QWp zEh4&ftsh#0i!Q!YMULp$;4bUdmE*3^tK=P)7-R=pmb$Bp^PSsG48U<+Cp*@gdE}VF z!&Y;Ia0$-=XG#hHGL7flatS#6s+z;|=j2J)O=1q> zuS*tCAPQKG@~R!6UcnU1h&C97bZ2lvTK4x@{Q56<6u#RJDI8hE@6f8_OJgfFrXQI2 zZma55@XOumDSf9@s$#7kmRkD!%Sy*;#eJnde%6&({GE+w+DPU~YI!hip2>LS0L~g{ zEA>8Qh4gRu!OD#u9=&COFm!L$ijKsq5KjBVQ%F?C1890e@;;IC9p3{7wQDv7M_U$( zaci9-FF>SC5eUq)_I(>{Z4)L;N>$NEm|oMS$U66`XP=3z&MP^wp(YO(wM5)oHb|=4 zwa$RDaXFTtJhQNd2L}bI{g~IBCxo1k#^$_-dgM4>3Z{EjN=iqy?~=Q z;xYKufbE(#C*uQ;F9QPa_dB|d!zjChD_{`k^zXHSV+Cd}9hDQf->c2kpD~=AqK$@E zJ4AOI^`}VTF6&@Oiu#Mkz`YWhO@6Z}OFB2&JY<}`^wKtKYFyp>%)nASn)q7W;^NYe z((khLAi;!hw$&;TNDf#ClzDG8P-^&wKkmHi*zF?P^{CEO?_?m-XEkc#b))@l=c=R^ z(t&>8a`?{&(sqLfCnE)Pp>G(vm)#@4muRD)jLrao#2KA%a_ zjCYWL z{5R%BLcRk6F0PtAn@?BtSdDkjw((B9F5yoHub^c)ykIS(APenM2)MG~=yq6-%LPM; zeA?19@pc0db?G(Yot?~NCo_x1yDmfB5mUVr$6vhNa%WHt#$%OB!`VK;Y9|iU!AC?X zAXCkaj9`n7Cj(1$_qCI>j1LlJPCR>czH}Bo3Uh0y*Ooprh*$eu$NS840XW?$&3oCX z`z}qyx;FfVHUX8Whx`+!vhaj{@tF;w#{n***CyEbjIjQ30xPSWqP_Q(cTX-;8@JDv zY0l<}%adJqCuMFPVRomF?CHJZ4@+Lv4tzJe6=uiSir(@yuChNV2#Xu!+gU#N{mq+L z;xTpkg?+<=Rf$k|XBuW>Fvoi8^aAmu{Nbl6>}EciBl5Um^EZvKWK6)VHHWimlDCDw zcdC<%VWo3kPBtkJNi;Zw9GRaEnn)hY+m^V##p;I?W~mznZhZwQn=Tye`GI31YsH#t zJ*;@ugO7WyPc|mHD=iAch&Gco4#jmaY%E=MZp2;=akXKpAF}6)`$=$Z;-QOFuG`ly zV{VEEgca|0US^+aj(zMAyhij}_{e=-zgz1H?c4PD$Jp(y%p1lQ?$z#6Q6+^S;X3e8evh3YzS8n@& z4;!BvxpXwT)+D#y^})7=i1gm50hjq?ywq(;21J#*%rvUz^9TE_ShLEOa8djHlt*{e zDYJt!gCDuVVfuOM{rf8KIKCW!MZgX{FSz?gS74r^P9Ml&}Y1slD0z7|i-RT{eV zT;pshzHTl5oaiHi>RJ1l9(zMp^HDoxZem)CPD3!rj*2o^oxkbr%Y-?g3Alo2X!o{h z{ZQbn-+TRZenegR);^dP7IK3k{ISwj)9tT>yRuc~2BaI>A;fsW8IoJj&&oo~wUOrX z7Xk`+*V%gHxMMYJvX+;v4=9%I=SgK6=9y0asLN=u6|H_UZ*d;4T2&qAtx1aKbpM7# zd_kEpe3(aTqU%;2!V0qv*MC>r-UkAD>JB*5K8cs6oEHt04|eA7 zpFy0K8COor^mJsiY7HB0UzXADZI}cIb8J2*%@iM>s#{p747rFKS?e~x$X91(8}Rk9 zCK&3thF5TZg0RH%Aj6_Dulmlp)EMETwO0F5iaz4oRIDqJ+0r>)#Vq;gfb!EkW{xg6n?A73%yrOXpWJ%#j@~qhCN+fa3?GGUhOgb^$ zpt@t7GrAu=nGT?@Ey`=SgR+%=3(Y`DKFyvnN%eg_xo2x+RQ_L10Mt741p|c;;4Pc5 zgpBS5?1LEqr{heUm}GD^ukE$4oEk$RXEllF=od)s0{{Djw$@rvce>uaX+Iv?*@xA< zJ{aY-Ro4pr`Yn@(hvV7D^3|=@=8bLCw>wmyoHu3Hv%nLr`%shqAKP-Y*G6>61_U!2 zx|l7_S8njFL>~}GC?zMzJxaQXAmcIIE%7NuP~9NA+w;os6XFJ{^4(>(AjhWm3pE5w z1zhZ?ij>|E#jAp^6h3>P3%hdr_UUxWH1o7DJNvrnO z&6v__mM)IU{Wnd@x&)p&H_rq zYtTw#qNl7QdXd>^y~VGdzsW>R87FDkX5ZK6*s{$(Do*$YZ?GdXvHij5d8x0GJvGhv zVvHE~EqT~6xfb$LLj@T!HG<)FE-*_ht0-f+}efBC)|B8hw0YlRej)_I$o zLW0m+czGi(gTUr^;fC*-w|zlyI?sT6b3M_n-Q6tT_P#{ zjDDp`yOGnM_QkQdq?^dau{Jh3iVK>&nAv@`{%5*uRaZo zK8KQ@cx#oFj%>0a&MaheCPYqy#d8O)_&no1oV;$=coreElJio<$ANyJcgDak5u)dj z^#M(bdA6`W=NaXooLx;O%cvdw!m?jG`V-koWzLEE=qd%fh|OU<wN^#`9jGrQbJ--y7MG5MaI_VKrbeM2{X#V4PxEl4Go`)};i zCmYT&->LFr2i+RFIV5VgN=>`*j>u?g@b#cMuh*1pg{1$R*Tv+7DNh=_Mdb`PZ{3Vp z{bVAgmgL5Uy8AU?>@}J>QDkv5WIPlG!<$2UIK*g^h}5mq9H*i6=Rrep7b@%^9*P?dV{FEc zREn~7j__NGLYqVpAOw+$EO9|xq<*1P&eXtTV^Lo8Z>PO`$-N*4j!GUmi}j}7()EuP zPV)8dznY9{C)lyD7i}s3cB%+t^H?}^q;anzsoAt#YeR*`o25m+ddDoV|879HL0#KmPVEpT z5P}MwxOaJehHy^PqyHXGbc{mln9Zp8m+vtw4t=%N(W89pn}wZ=p+(6KQVlvyxJ_|1 zgz^rnQFIQ6uqWQM!7V>xuf|q9ZTU7U>0Zf&gO!bIMP$Ou~~ysAe}Dd|bYTPW;&tGitwNSe6P=*=*P;4@h=@ zCP5cu(lcHRvyo)`*`3jWH5&cwh{XghD=DbE%vFseGk`W+0!-0ksxj~t&#(({A}hyD zN1-%fH~7^gCf=Sa9ap2MFv+JPCsqsa!l&M$xU z@QyV5?~kXrD{rx}+@;NY7Zmu>M^ z5L~tu9JSuxCrV&!Dg3;}pF6L;kP-L}?+-+?iL$O;c!Yr->y8m3Ht-Eo>P?cRyQp|V zLDZe8->u}MY_3I35i0v~kEKm1zRSa5t-*CVvl|TRFpD|4bvmHm zy>CS5B+3+P6sS=^5_yHZU}?2TNSSYvHOB7E6z2^_4fT6lm2bj-M-P+M(JYBPQh?CF z$p+3Um*yGd#xPNj-&4*Dx+Q=8ex3B?|KaN_qvBe&wVmMZ9^BnSaCfJ1g1ZEF5AF^P z1h){NaR?5B?5AYbxw;t>wogH$}p~kl znKx&?JLJw&RBY`o9yg#eCeE#=CFo;WaR1h<`EFSe!8-YKHy<>(|B>zgO*}B3UCe4p zGmvgHEOd7AG2ghCI{oIgQca_!O>vHfj~$a9)1pfqsJxf~5?(K$RDRBbS;F zJsKRJRJ}NT+*^BLH8|X!)=9?PlwT`I>_1B}`vX}CozzlFtg_{(IsJdsU(wY)Wt~_jyY^+|x zkIOrV0gZo1tjIkCfmU@s$h*<O7JhiA3@HZ1?e4RT(3~QI3=L-XbqI#FjX zC8DY9K(HzJ3<9x139vB3s=&C&?QbA?`*{wzS!yBu04EEV7q8-!M(QkPI*#kLned>q8cCj5l5F7~}cJu=I z3NC1MtXey4s|C4F^jX&!^v=$oU}swTz=~5B&l)y<0R2^1Sx5(4T4iVn+ZdEQ%eRdrh}BHJz4u*uZUE_Vk6 zBQ#~AytOUmF*?k6lFEFt6AN&(>oQz7pP{N>n;n%7rmjFF5eps>$0 zIm|2p>alFn;`|8wCuj{|CY%GPzo_a)fb+)FIxE{m9z7bxdQC%zlA}{bnv+dOE~~Z? zRH!q9<0N2Mh7&~08Q*z`~eqtiIh<%gpMBH9{4gWc0f>THgd=k5QHt-sgPPOSD4x{GL(2 zKBzIbI*5x>o^sMyQ*v@jaOPfFzsc}OsK0Eqs&ukP(8WiE%x^A)QO^*K*NMO8;S_F~ZJUtjq3*qHcr!qb@EDn)d%x$PQQfTTe zfkd_x5$z@Hl(yeX|M=CG@oTr3D---?fLXGX+(cmi;s9dcl>4}rI%Bf!wQGpRGZ*FV zn*Zt1?j8fffifLX0%>fJw~IX88^J#L)yU#&n+-H(LU_{sS@r>zRrmaQb9?<>A?Tw5 zyKIu97G*e^kEN6B+^#n%+Y=4|$~H#b#ko_{m~feRud1@MXfHyH7ljJzeRew>C6P7v z%d9%|nii(FS$_pDoUbz{wHGZuIJF1r={(-?TBthpW=0-KO0dwOLBRtQ;W(tun&CJFIE;>Rm!sg=SIDEf4Dnb zQ(fT89;JE!5-aJB8`5b}))2L#=X1-90xO;BwyL8>3vLs-PY&~K+G2PfWKT&xg~U)oL}z=NNjxkU~xz`#dXqqZLb~Q^DaPh_SW1rT2=C1`P+2j zIoJ`sbc*4LL-}I$0y1kYWx(mu2OyCQ3!%ov(?h)=|DN9=`}ME^+r-0EU&esprCm*nD%zLyyeCOJ)m_*0f@J~?C{-Mb*x!1Vn-)U=$fv@ffu zE}`N?#Y)HhbT|lGuCwltxp?16w}coTc_h(q;0yyW4dU$ZK&6z9FrqTRHL3XU8-GVR zrtH4Bt-}<+2*-^HYJ@?vJ(_vkhN)M?!dP1**^m%88^9OuoV3+lfwPu^x?;8q$%1~O zUeu{KIv2`L<+|r0vOx#m*42y*c4$pxOaJ)pE~-22H7emv5{UU_58N!swnAO(qk4$c zf~kcqoY}+S$bwY3eg|)%2DdkWI^nx{0^-csj2Y3KI=kTK7Z|%g#?~72boKjv{iPzy z#7J2amLS~LMyF3fuKV!Z?9two)oo4Q<#<%>Sdx7O+*Y~~;%!{{88j;yny=GL(APj6 zlzp{_SV7IOJHAiq8ik0*u06>_)dt?n{KS@u*eCSWF{AoTn*Pc8T}mP%nmm0Ub%fOw zX#zrU)WGlOlCM>A1J;6GHHaMCa3w=M51}$a6;kD=rLt-9|yr)4{?^MI1y2F z9v;bP5H81IX@cHtioU=dxt&Dr1WY=FNsHlx%unn?&%vyN(lb3qnaHPFvq*z55*6jA zNWPS4?4r+(l{quQs+q%(n#H4P4a4xj7nf8Nt_D4}D9Vv6{4i4=j?IZIRn7o)IE9Zg zm^{U-ZAd7wWCX&xU*>Twb=1`hA*O_vu!90Tmfbi(#_9vvGqQS%m^b-)m#!F=alUW4 z11a?3U5EX5t3#0DbSV0YksH&FZqQMp`;U7VGWjE0w~am;nhg<@ArAgPoyuhR3~BRe zS(navofI4?KR!EEa3f-qav6$-*3x=)LG;nbEV&;550~ar6V}V7L&HjwuuFjwm+NAd zEobx{5q?EzdH*TIa9fn7BRzMuNOXB5t(R3Yr~jB##}Q)9bUy~z@cG0pHvFeo<6#6T?TvCqL)vGw-X!|2Tp;>e$G zJz)^a=O!+1oWGqu=OB{pm^>Gr^$%$KN`*y>R?`=8Q{bNn4ME`~E&EmnfA^QCydjEQ z+&WF_@lG7le};PXE=nb7QPwVPC>;Mi~5ez)S0t! zAye;`ftX$A##~z{X5#n8Y64IP(ZDxX?B~?$QszJ+LCZLU48!@a$3KfsR4y%17`Pt= zHlJ>#%UE1C#2$XY;>+U%DSMUJNU`(SZDkT#q@4C}f4_@(0z7I-JL8`rANm~i`3$BB zD#uIaPdiIt-Fq?3@{jIQR1_p!vzua%iGXk80`!>UYPu|RFT*LOn5O`=RP3RAuo8p( z$P-YzWCZg>X!n7@L0DeU18&)_R;);l{tF#Hj>@fT2-h=NbT>ZD3U64vp(1W^7{zO) zvhqngTC2*ViT)EcrSZ6jF=*DPw$kV7hv}0PfVM*fvv!@O-BJUUFK3GqTVBIaCa7~W zlPUFsL7rbAlN}R>Aq1!8KKPlwU_IE#$Hj1%Owa=hI0P*TZOHfGr`Sjgi)*?(8c@G` zXEepMX;P73x{y;Tleq5{rg_ZN8qcGe)ZHPvh-4Vu*thoBr8zhI?QVln2J0$pd3KU? z@U`v z9_D#??7mk^<^sfHT%ohylo1JpdnL%s3^%0gu?GpATu5TIUp+@%Iz$bo5{0X+NKKm3 zy($Vb-HyfY{T?Q3yOSH>nAKF$$)mZQVMbzV4JtTY>isUeqmBi>ji^d1;7GqF5bXFJ z^X?Q8j*$L^@#c>F8=;hXmQj}`GDoRT2t+kxNNsR^5Opth_S7RbIN2N|R|_cq0$~Lk z5jCRUK_o%$Zhh>HL$aW+zZ>0D9VSj{R^p!}9G$zi+ zfhS){p3RvpowWVsg>tZ9FJryIDOi5!hKPS!fadug`PTp-P9BD7++X3-<||4fLTY>~ z8e_9V+CGs@-(N;y-;B!75;JYDFSb&?GU6v_`QG9hX}l0-xInTK?o|#z zYH?W_9uF_@no|4TFk^$l#p0|h=sQi4|1+n_J)f>D?lwh*^^A^8bQ)`&3&IhBN)RX^ zLA7^e|Dqj-zKj8k6)x&Fzq%QsOCFz!C)$Uo&79V=qVF*=t|~1XufO4_UslRjT7JvH z7?0&)yzProH}DbEJ8Gj2-Ey_Kx8J!xUqI~@E;+GCka`@vF}pU3kcq$b-JdHwm=iUv zq)=rabk7ql@M-C6Ook7N`M^o$7)a9-vhu}@NkeG3vZ>cI* zv*$Jf1PHxu+iOuHQL6*nFkM)2m>k3>76A{oE1&=j>celzs7Q|Ptr4xY7P1Af1)>3Q zN=VULE?dt#ZdA}U#MZ|{!oDg5*`2vN0=q8Qp?w%Pna&dC_jKVaRd1kva=Fj z_YH_W2@DXWO-uA{$BE{3lPFPNQLU?irp*)50?1Pymh{eGSa>KOoRO84A3GsHub6h} z)WY@Q-F4D=)QVt(9f`|WUOpuUVIqBZ)tbKoSMTNb^ygtXN!|GI1;mdR4j0)PpZ2f` zVeWXCwHo3DfgK zKY4ZJuCPm}2q+<{0U?;%Al_>5?P140RMc7p|Qsm#y}DW)*9s z#xlk*5d+eF1ZUnlW4)oi!pzqZ482GtVHc&uJmFYq{5PMC{bD9#k(6HJ5l%!A#}~fh zqWsma@v)8k=KkVPGaB1ktg8@YT&9| zxNF)hUe}Weh2P08+|{oR}OiK zheuJ~;Fc{*t~AgZ;;Z8;=8MT0g+bVTIgrZFTDHxW#1ZVe)?~tOVZ~(82@{mezZzU; zhD`W*&zQ2+_g8=B70#p^{kj4|c;~yGLvDa&7Y5RKf3JI(bJS)7J|Wfbp4}TvF_g{x zd}3wmmI_o9EK80v*lSt6b~q-q8?;$0V7Fh)ym13seVaj`3;J$|z(W7kxf+Az>x#CI!pv!eATFb9nZO97!$4F4ffe#*M^4$%$c#RRS4 zep;q=`qZU|QUycTY?NGex_;B4^bCE9cwsmNj+*?a*#}-E%>SFaa!;6vFzW>t$hxj3 zTs;IyoYGhrdAL;m?L2DT`VOh(iDG5;zgPe`Jx)`Bo7}!_%ohNisYK5ZH zvz6F1hP!9iibGWUm~9IGgcRyC`XdRNt5f=C!L@y{>fbzMUD@y6bdGzbZ2cjy6R3P# zX}#x;rGO~QG3=IBmV1zkbi4MLAe_8Uxtw9%>vsyK`229emC^)PP#iCC@P0~tLn=BL z^YHAvBpM@1h9F4GE|^lS&C7$Ndv^pJ>+Une8RXl>LAZ^qB&{a<2*zp`o@$Cn2~Xmj zq5nFMIVPS(X_t^jy|*(p=tnp-nRP~gIy1)@R{z@agF59+_CNwH+m(m~H9F#YDMfkO z=0!Xr&E8-eY}=%5JLWAB0Jkftp2&}Cyt`{)wk04J^z+w5tTNjatW@E}l1S;b)jL{f z23y@G&1i7;2{_6rIZpe&H9(x(0sR7eGLG2+v#&}-^G26F4NMWVR<_m zkQ9`@91IsDBhj>W z-LK<$Fdizlyxzq*viW5n9L|18&}Vd9^@#+bDopYqq;c0-?vBXh%{U(8yGz18(5c(? zVc0a%y`V3J1iSc)nfdqG8bbDy13~=myR8g$wVxrdJS4jzsTjnArrDFf&mzVR83LL= zOZ8qfR-xSyg(GCoQ4XP^@II@2BQ&ePY@7|K zK(V@Ixo#QEtUHgwJ_Y4)l$xRA;{}kw51P228yY+Yyp7$1L3^%u0&go&q#FZu;WG!# z66PO0jbN%)UV_e>gU~_kJl-}~v-{OWMN7)^?KtphJ*?rd0K7wnc?};gBleY@vLw%6 z?PZUG=!!KAdjaYZ^Yk;Q z)~@5+ISNKPlTycy_^>-3CalZIk5-vX_3p-ljOTH}?PBM7r({RQNb={)#4c|*`1ziW z@sun9K(Q^0I|3g~`Qq#HJ6{*zmC4$%x1`i;`N71Wkm)SDvXkqZl>)Kn`yyB`j&6~Q z_rdGVuGF7CZ2g>IBcogIdVM66@B3Rt2w&79+T9blK&b~7@20u)XnhYIyNpB-YeIiJ zr(s_KVL;3|+Q$5z7UBG3+Scs7uj{ZMmay(;mtMRA8QHDC_krK222g{zvnAfa(*E(z zSc^K-g0?joy3a%Tm0_>l_HUZ)ednohxqER@7$<}^C1P$2ANYHZ!23TXok}_pkq=CL zK!IYKll~N=vk0r|=dKT@nFPb_lX_NzC>C`iIJq|X8}gyocsg2GkB8Vuve7CWbf|lC z$S6jAg-_DzdH`ZoAY6aR$z0sKx!%_%ry=TrMk}JrHa5+bqB#0P;cr<^;NjkGE2st^ zs}5Z_CkLsAViIzG+a=%B`Xsosfz*KLmKj83qJXv?AQrhH0cX1Twk0h8K z?6lTVv=3R3L3$)S6e*`DF6bS5m=Am+m>RZtc*_qGI?(m)$v)WhcKaTCnfw44Xc*Y} zHroWwA={V#ux!_z8Zl5AS8LEJI_3)s`;w$K^-5qil}hwD^sF}0{x#-}X!phgH@C%j z#~?V`iPSK^U`CX_TF~k*1NqrG(DEQ@@>9BkILF<$U566HOVYc}z7}Dd4$n|Anoy;P z^6T*kV5z<5R;^_NjOo+#Q$r`BB^$tby0v9dkahsnf5-8aO^Y8teG=`b`?Z zSV@m5qQCnSK0)p;v%Rs5x%f0y`Ati?oyA2zV0G<1py~T`@OtY597OpZ}mJ%;aM5NxA&Og zwaXdvbb|3F9>=@Nl^O$B^0?M%ZMBTn6F6Mcck+m@dL`bv-s6xw>m861=c2Wr3g2QB zPWXpp2^c>Ka*dPWL4-UkA1Q}ajd=Ix7L`Jg%{6dXlAb3LW`7f@8&Tg6mN-!i&rtQf zHZbgNrnbPgLmcbcmLK&ze(-y}YhS1)J9B}+0S%JxD~4`2c)KMmwik;BkQ-O1P`-Y; zu5aQ>B@Qq+p<94wG~9x#;t-kz-Xhb*m&uiWXAP0wUFu~Oq3PRvg%jcz(KEL@45IDc zz1x(yo8661CuBk|eM3OGbwcf${nk2pJTndg@+lRj&I?0AE4WU?!{lD&SV4=lcq{d| zuA6BdfjTfNK98H_8wIhl^E&q}?4o1~V_6=GGk*Tr#W8W<-W9M*wW{FeL;RfO)nOC2 zvt~&cM%Vp3rkfngh|TNtOY+HFm)kYgnFrEndf`+1Ky5kAX;7_L!2)|8qWEQ}1AU7$ zjZTm2LbYYy@9E)8GEZ55n;y}2Kj*jax)zzZ z+Jz*1X)8orTjtip-8W_7`dWwBj-?+Qd&~bxG`0+<8$KHpJ)d+=O8bR96d#%e5r4yF zH-E1#j2JI>DlP7)MCUJ@T2U zkKe66IaH>!cO<1n!Hzdm@B!os0728M2oE-VpAY0{5{k~jiY6q-Hj(QADMu|-VKZ@| zPl%pdZR4>Qrl6zvvd3w@nHsRCe(mFZXYt{CR07s>4eqAAcN~6xG?_RSX@D85DSJ02 zgSO!ZUt=86Y?XcT7<{W~85*qhy8m- zV#24WU#0?GH$1zUts32Iow@EFicNcHa7HzEZihBNeU6~P&8T0D#|-mG|zEI?iCQuSUD&UT-Y6@rKah>U%2{!!|>(7E!QAJI+OzYp;7{3}qn{;J4igmE;0^14{0 zq$hEqK-`q)3(D7)lrf9xEw=YmK&Wedu&1_7Uvc=3QZF6K*us#_QW?T$KvN@B!>@^jFMu#{v;F0BK{m8{GR9pT~U&=|18sYAnjB>w!fj3 z;)h3IQYz&kKHhBU6RAq0dWOjA93T7BMN|v|@h7ua8 zRT!hNts}dD^R@v$cE*`#;TIYF?azx3G?4ZH-<0UG_}w#bqoX~XEdwXM+E(jZ&!+xu zv_zn;&2-;!UF%1SPMk!SMGgtsv?~KNnQ?~Yd)pJ_3w^JFGj*gBD-a(K2{ECut{SUr zKHX{%vA0jB?eNu`6k2&!?8)PnVdkGE5AG7?F?YS)i93bi8@LZ$l=af9@>B3n>ORY+ z-N#Zx@Z+C*;w_a(t2i*H<`UY}pAulE=QHe+en1 zDVvPa6iF}?%sq{q-%FqEl1Kwr* zH(`%d0Era!;ULBR9q2P+>?9e8Yacqa{#iE3{pJs=>CFs3*a1on z0o3=#uzNxEf{NFl%ZIXOi>= zs@YFC?&E;`w%YOK%A94!#u&riMRh^>?UqYnQ8~kXe<$lCjrr5H=u?9Z(U-Je`zCve zVkH}0vtMtkqrTAVn;ic)rX>Fw-U@*H@&v&=beZc1l+Wt}K<4v!Z92{ivdhN4O0n)y zM-r0j0kZ}QxeafR%Bx~eYP*!$*PkTYXYWQX()FwD9PB(tuSH`luRC0xV0FjGr3zAS z)|SJ^gzM*#FVAzlp-B_Qb8H^n@)v!V$D2`mGv22uk0xD4`S<5kcB_|n>a8b#OHVA7 zrL_62={1BkVhBh1Zh_4xt1a7F!%1)cj{x1cr!tN8#oM3~@JxQ6&6<6qTM3TZi6MKR zYH9icwps#J999~)84N4*;*`y049QK}W{U<|J0In$YuYc=0;yNH@fAn$-`%F~#p#Z$ zclp!FC6X4o-0XihWb9vmG2nCj$-1~Ur=)r~ZMb`HBIWvF`0v&eB^`_`d)dHF9e?{> zwgjL;0(Z0qcFjoW>v-0!aXM7c?d2H;Y29s0qBYqnZty)}{=<(_zJEp~z8*^ZlaXi$ z6=O3QRVN;=w@LlscnGEPjSD?Zx!YCoIZ+V`Ln0y1ODnUbkNAIRh1np>(K-gF4DR`( zG5DlTDyTXd*wx`ZZekM5Y9ivV`^l;yxAw@0L;e&3?@`z-x4^DXdA9CT^ask)zVVp) z!#3#C?nDM9`qVM~wVIgRSLb!cDG!J3%LMJuaacPhn$6+%b4S*r84LyerW22_yZhcI zSU{_5pJTQPH%a%kshaETGbCWCXVn__KwN%++Aoy{nM|s$3+*3LYfV~pKRdX z$^C3tgX$+KK;W| zs>va?pL0*ZrI%dy-lQ(2mi=kK0~+I!ZmEYaanbJ9Lc&q$j!IJN`QfL0|0ch!9!2$P z*GJOY_g@*)MHf_?xP9pp#Tq*%o-9C+tI5VwV&q@AM@E#!MUoM;R8$g*>GB1bv^}dQ zVDCu8xU`d%uR`WbgQJXy2?o3#3o06+Cry6?>x%qHZ3`0aQYLCO^AGhW|a8i!7#uJjh_UJt!hf zHk@pZB?--^!yU_gS~*Z}(px;FaV_|ReiF*P+e3VAV$Hi~fvS1md60JVJbW*=g2F@S z6clJj#B+lz)&@nEzq*F)Dvs>j^v?|nChGjUu*o|*T|~5(h@j58M3&b@TF9)Wiqx(AZ&<+YbNjBbo|I zr9qK!y*oC18d?N2*sHwzxzTOaSVbg_CJm=lN1&!+ybTuv)3ynJM302Sp~pw}rA)C^ z86_Dj+-xfxk4bm*>8H)%?1IYC9BX6HN@Ll0-c;M3_8VO`LRJf}BS2RZtxmRG8Jkuy z=z~Govs+&@-RvIpaAtvR!`ZIU<6)zH;Jg%1e=_?#O=ukoqZpZGkO}u7ABgiW{m|ok zAu6z+SYEa`UeMux|5w_Kv)EDbP`hfuVx?~*#Hsx&m_EV%Vqb;y=xcL^DO#%L;TUVe zh<2iw0K7(&r%tk=B2Alep5Xk`Y%C$#ndi}9!&|$YU5;cmRZ)@qXNHAJ>b@x zSfM%1Kp|;(!}U4r>j%Akr07fgm@o=TpwQO4QB>7NXieK~OemhuZmC8zv(E~OhhxN;)y((_zdqw5*lC$z`HwZW>e0 zmKZBxd$Se!N&FZg;;RIFZFMk#vd9J0I>sX-ED?p@Pv;CzrxHMe?x}i-9cN z7+z)$MTe>mt3K1z+I1!G@=I(RE$fuS%GYX;L9?Q4(z>%90h^eR^MAspzs)3y|4N`t z@+!qxxURr8hYJngv$DDBVvreS*`G}Ja}-j@)3H&!eN4*>ctmOpx`(EIUTZ*|z*ePz?7TkE0xW3tj0GZfvWU@(j0wq1R>ZCav^}6`0 zV;em0FyT7Dq0WaWs;3y9JPc# zKqQdvAMsHpzD+`Xk?m8$MaBG#q?I08_WWa2fjzv#`KnCA!0Y)7X>V8Z)>DPU#S^~U zj;+p@Hg~CwH`vs`F&$R6`QKVIN8|JnarkbJZQxxX1Rgw^H?>iE)=z$a*UUkyv6EhF zz$eo-OcC69bvQRHK&*ysiuiZSw*;w_mq9>Qflj#l(ahh?7zGi$^Q6lc9JlLo_B2rk16A2M&y#A~;Umhtp@vdHaN{}M z@OlV|P@0rflBRwPa#3Agb|k_vR^6XLG&9xiY~0u)xQNsoVN#yF1Df3VlCpxeIUq1HsiY)8q2SkTz9STu zUK^(kdSYg05p`=1bWQJjpr_-y!BAMKDC2iWDCChgDkvLO>61%=Z2cIkW{L3tuN}b` z?7s1dKU_phERKBA5>YFMAKt3{uF#s0ePv?;0Xo*x3>uuZKDYg@FTWxlbG3Dwu2=)5 zT-Nh-pX?-9WmEMQiJ5{x?vvXpF{5&mUrusc8cU}huVXVXj(A__+RuFgJUJlx$VvTN zx8ZwUcVNNP(!VG|g7?NMtNBL1Hl8a@yF6~!yvJKzN4u*MOONW?|0Cl3Rv+^%6do1h zpl|=ba6%YJ%OE9ERp4E!Y8OQI54FsUShMVbVKk9V0a~Ll{eiIks;#%d=b->lsmQiJ z;SVWyekgTy3>z;A2-UNC;2*bn+3}w1LI;lG)IWy>$9x)wh7I$3<^}C8NKKR#1j={` z>8L}apeNf_aB~Y(-^66kh51#*!z`Jt9w`$#=(k{g7~qQ#TcX~m#`EJKZL@rw^27IM z&-4I~{S3Qbo}6b2pE3kKB4Ldy0a>}s4_|RMmHx+4aPfcw^r3#ESozCUGhVHh3Y6f^ zRI=^^cqZaw^nm}9)nF%<-~tq%3xX&P1)ax!SZig+%b&^9v$E!$vORR+dk*fJj3;0{ z0-nC$82*q)6rdzI?ZNbwvrc@xpAwpa|3WE2`HmxW{s?~?ApG|qx#K^k zC=o|a;{3;o`JaCTr8hxi{QMB>eIq9PH@OFj&OZ(%E7q@mNNJ_*nl~1UMu2~%c%fG+ zZ3Xz!QrTd%n0%J+)mqetGKK`W>H{jla?3HtOAQK9I}VB=!pPZxYbci}LsomNt@96+ zh|OMSGChC|_wV;MD0%*rEci>Yck%#H`&1B|q2wyt<6q`@_Fl8pDfq-__WG0%kUKsW z*7Q3qr2$uoFr)h&dk~nldYm+Jg90WjFP6~{+tWW;Das%A!Ovz4QU6nesL=SHjNRMZM1;h% zQ+%@ZS#&goCsW9Mc!b#L(eEs=!GB-%5PTzlfBf9deY8lidjE^?CPmZFm_f};Kw{a% zz5K`Db4*=a-{dbDO=_`Jgm>Os?SEzCh8(_({-B6#t804pJpQTiaDBwUV>6ll{Pb9k zFH&>f_+}m$XFz_ot!mtANdCM%tlmCJvY^?2xjV)rpe1fL0Us)zL4>Py{Y^0-CZc)DYEgC zl2fyfB!WqB$jZ&!kzO0u=*f!M-!HXI7rAf1L9${YUe}+L_eVKuMu$6MzMAxCzQZSK z6g&XY&J#ENu5**6hM)TtffREIub8g{2YlwfeR+Q_FtFsVSZ^^CB<`=l=Esw7MftuM*6w6yXuICPK- z-WJrw56RHN3>gtsi{r9%_CH@7dK=W+3(BW5g%E=oz`E6GIPl-`Z(BZx%dU3GBMb)V|=yZa}4-a^lrXO)`N(d+BH8lPNjt6jW-AF`8{Y*lilf zq#TRQ4)pFipp2vSXF&e5J?O*FhVO`@_YCinRiOoIp|udcp9QmRKt$f7?0qLg;iwqE z7cKpI`jbfwgMwv4CA;KW86)UuIOg()u0?JS9TFGEF}O+{l)PXQ4_fNfKAPKpS?WN! z`;tg6svr;38`=SVIfN9$#}b@G;W5qvzEI*D6yjAj;V~K%wi0A+pPrs3Z;rOSv>jiZ zx&g=OXgSk1_PSc0pIMx}y{v&jLL-)@E72}MbQgspv#&efF$XW5iymRowwSP=g5)#lNC z;0lxDX{g7=Ik{pU4aHuyRwhQRiQ>&z39hKi<}1hLrWm@+rkqBWERkTxWd{uF&ZwO( zxg-^_!Ohn@L-NV=p;zk2RtIm;XyiGplrqx8SeFCS=^|1GlH|NY$?M^!$DSCLFwt^g z6;YUjBel}`6sX&)AT<@^1b?tP-IaaguGCWV+)1tVwcw~q~z&fkmX ze(`?I>oo1oeDiM;_}{Y%okz-vvMjAP?CDnhKPd3r4@H=(gB0d$iU_9)m?F~@U{GcX z!~*-`=~hhy8!|7o1LKG_LhQKJZEcaPIE>(pm6OdcQR^&!+ln0>^@brL_Z$@8;Ku<< zwtWw3%sW@rD{V#B*C#$oJgYOoHdZ7GW;;$TjURXWBq;=9l~= zk$m~r+7=|37mjUt*i5|F>M!`kDu^J%+0^*Nqbx-iw62tYE|GE zwYr2r^SC!@J$5?-JG-*#d2Jr4fB~TcGr5=s^_97*#HqsCm)2!XA;?P@v(5hW6-ATU zO4Gz;)`$6?MNMiDQ=wD1E@=SFj+h6KGb`_lhc@jpQQZbwZ0}D$N zR;j-1OQf=tw1=u1zFl(d6ZyUTzN;}AS{n%oCiLUKy zvwn56$%U89k36W7m1TcTqFM?H{=7?Xje&yj?x$Al&W=hl zW&7tJKgn5W4nKV@XqRtGf9>>B8%C;1{ui$`&6;3*hwe}JP!f|WH~1y%G>wSUy3}07 za;>{>K9b#%|1t8vrbGOLq&RJ+xvk?#mRQE6c7+<*(3Dk7o{7+WnM1isJoQg``!7E> z^5Mivs}y5L<*5|mL8jk_v|3ep`kt1>x-HJqRu*Ow?=`>p^z-GilNJG5prt&94ph&i zBqehrV{Bg$o$=wQhUZkr2e&Z4kG3b^C7y;-s*4n>Rpz(`Nl}6><6$6y`Zx+5YMQdO zQH;&4OTTyDhDX^O2H+#?R%I!Yu@ExIzY8%1AB@8v-IKor=~o|X&?$T=%~k|sUWjRz z4-${+A)F-QZpk)RR#O~SdD~w+g=@b*{B4vbtz9{Qd@$vt^7H9k*(V#?FWcJM2;;-e zRl}ZZC%5n(d#A7#SZ##=a0{@)7<-=~b{W>MFj|{eX?A{qb3I6B(xi`i&cB@a^p+)0 z^a&6;D7ZHCddgOrd(QRBJ#1TjW5rbV0I1u!{VE^EJe@sJ+MjSW+56t=b$u9X4ingR zPFI4s7m`OO&(PLy8^U!~6)OQNq$CUTh9v_~=3kU$`R)g@<5$M~0*(-3kNe3$U||FP zkakNbvF2Qz^?b!e)*36`B9z z=5XeQ*`Jh2M0EKT|8z&)hBt1Y)74GG7~G7&>e=Kv=95zv)m6qatStBQJ>ti%vT-?! zp_H3260K6pSYPD%w?}Ea>Q0;=SIt!dcnT_7027*~k0KV6~`6Y_Vh>Cw*r@y2RhN{-t zo1_EMlVH)UDJ6MpFHKDs^PkuEUj{+^SXw+wDdkIxOdJ6=k#cWu?+@q}oqQ>+2K>K! z5dY&=MCTzPxih6+-yF=)wEJ984<=EFr7|ga{2yJTfOhRtJTD?VJUJ;T2@#M=`yUR< z|2A&~ZGIH?+Vk$*OcBURT&9}03|paq^RF)dyAh{E8X$)YZ`%!N|HNg1VASpr^I5Gx z)&1ARg?Mag_&-l>J!}YneMuHqM>;fXtOUB(H3zLaX7>!a=jx~f2>$b6grlLCSooDS zw0!j8R(}-lho5yW71|Ym2tcWPZ+!WicTVA8Ld1Xmy*bZclW}r?f3Kmgp8P%C@9IE8 zA(gfW3ILml#b@~ti7oek{F(*E96I@L_xJW>>}E^Nex+2GLZCH(@1dRl+BvB5&r4G; z0oreBjlgDy#m~@Fw@esVSi76!r7b|Hzqt4-qn@BVXvu~*lP0A9$E7(ziZ(E$wRhPW zO7OVcRcLqFf)Vk(q%~B;XVI~2;j$PC2jl)9Lx++U!rSm-48rs1I5UrD`XW$~#i;&y ztj4-<(rl-m)%w01|NN!m*MII2*pbwT|Km~#BP(D=t0h29`E$*lT-?!Y_FXh}&)BpfAE)?TA5B@()}f3P8ct>K?C zui|OHTXG}dH1pGtV0Wq&v@mAa%|uv~jiiT-H6P0cUBFOhDNdl|S4+!`nOw6a5i)z; zbmDPn;3SnhzgwZTdl8)7&Xg>v)2 zh`c?=drSNP8`ybCT`Jsf32|(d>d#Ls927o+x^(l~j$25v0PFAzDFLwDfpC-qjABj+Do$RBS%10ByTw(-uz036r zJc_2Lv4E>%@5@B@3wVvJtqs5H1ihQgD@=86+2PEwflMeE33uk4!{S%pV$A=(Chnog z7c=;Obe&~XT-&y-gF~EtNuEE{i-QC^YAvgqgcXtTx?(S~EUuExo&ONW)bN|w+ zRV&t-Yt1ow|N5AADCo}>4&1G7?)p-{@LE%Uh>wghLS=;__kKV!rkf<63%Kah`Rcq?^%g{+Gi0&mLFB{pXg4QEYVS)0}HFWh$_B8Zn=% zaim{twhvBL_sr>bvpSycd`o+ALu_^0hU+NE;U=Q`p+Zd(CY~e&z2Vs$sbDxRdqD<6!a|9o#9`0C80K|{RBYmS zz0EyLSrQ=p4ud4u;Z3+LROa)RW(;@M9ht`1)^x=U_?||Cvmxl9$bPBa_B~8Ke__JY zihf7svt*L=K6`Lwrn${vQt+x(%JPw6Nq+@sVlQaw5i5`1bcS0g74~g<CcA)QS(^oT|Y4Yo2|T8WpsoQaW7@nQY_9no(P z2~a!mds?4{U`H8xH)HsVF=>;>*P;$Gtqp>+LtI{vHi-3>o_HBuRkO5}s-$@5&xLnx zpB18Kl$M_+l5WH89I^zoxr$yEtEy2F5n@jNw3_y-9F6RI$t2xJLM62aIS%1Z5XX35 zX2w(+{DO$4b>3F#c1vx~jT7;G=n+EftDfD6lw6yj7(*x;UVK?5e}^rQlc45@;)UJ+ zEo)#_a_M69c%u@P179p6x?}~DDv7C1x{CbfCyO-qNksFo6Qj>MZI>o;xrt_pM2cRm z&MQQy5MkA9@9*LpqY|W!2UvImd+1-XvwN=Cx_mf|C=|n$-`Upu#dgrY@R2rF(htqD#(wda zGxbRlp0H^%3l8R3IjS>kYq?OM- zkX~bF1Kjb+bJ@e z$KeD79n+hj5OIiJ1OMwA7Wl_4Vqk&e9u_2WS>HM@b8fL>=x<1^?e|SW*LEwhHsFIs z7D0;tyxm0oK9en~9!S3~Sm{S_7Q81CfLE8QOtb~}5G;wLu z*bp;1_De6V(GN}I%|LQ_xvLJ&0}~bNN-SQ{2w`|dme}_~Dxpz|gJtz-H1V8~!NdY* z5`Y|e-2s89VCHf|sxD&b{Gv}!E75V<$T*JmiOD< zB@FLUojKc;M(LspIJS*(JdZ=l&l|~X9&V*l#V{JpW}$8j4Hih zUXM)Q#>=+&?~Sbn41GBR`4444FK>-H_(NPp8Y|zff`VZd9I}o%Qvpe8n87%&mb$IR z?$UEamu0RO&&@$)nP^126p2yf3r-|DpovBPFZm(+ANfJCxBlZ?!i3yn+P>T#l9^uR zXro~?5!KwxEkeEqvVvT@myg3lcD^oIxTFv})eVfCKvYZVk|Q)#o3yFRaI8BE>2;PI zmB+y?(GiU-&OQVjV9Pkux$lt54=F~r73M-cU0gvQ8t>X#aHiBTYJJ|7J+AWM3$EBA zh-=)Pxlt2`Ly^>LB7>{Z?{Fvk|4AKT+5g8wA&id~FCnM6UaeDa@Qy;UQ4R0M4(@*a z`mHRmgVX#ougv*sniY0W=NCAqT@=O)R~8#pn-exY9Hmn(U!NSH&~+J+g#|TOvKpN! zHs19+HTxQobjqw3#uUPWrLfm2jr>KN*7O{A(~P#$I*rBegyKM9@))z3i_jvCDBfLC zLqu$@#5^syoPE4#&P%K6(;MR}7*9t<-*5Iac*w;OT#*$2(%NOh#5U0mG{t&v2?T$I zOI?RyQ&O{`*OEw?kZT9E{mVsZrzi0CQISWv06!8=`Co{E2`7AQ$z%Cr;?Ly34*4}8 zouxm@L#q0;erwcw&h-~t=}Zl-)rU!~{OC(|ZHQ4X66x!8WMWC*Vn>$Sf{h=lc=7Jj?p%kyTe z1vRcVnARf@Gpu4aZg1OUV7YOqPo+R7$_XqnGb=MWdLdh*;_OB=bxZFY-^S$XbP{rS z$zbws?z9q+5-BurTHSZ5Aqa;6o0%_)Y7Vo6_c)I>nojH-8@xh=mgQ;a(~m>PE_R-8 zM;rH}EVs9E-fZlM!6N||YxUm-SEda^$T>S)A0ndyG+spJ8KqM-Iz8D*eO`atoh*zy zu4pUnlODSx`00DonrfGdWNcNEZp{65-y8fsnItKX^uKqfZYS`G%m{!??|ouYSXLQ_s;^$9KN|f;&5>v%ZftqIdR@wfhn!8A=&@+aT_eq4VyL0QCQeND!~>B zC<6RkOKRbFNTJM1qVW4LF>r7?Pj_xBe)5SI>m8J#^Y@%#nmu zAL*l*|E2fX!T_~_b1<7!!2Jw^%t^M5D?q)&>i~}rLk#?JHdLTyUIN8BJ4FYNn{WL? zp0uq0bvcrNZvfIInv(i^czf)M#a<6z4>pOs1gwy`@?It36@Hp@3KqMu_4d zDFgc^ZEVnY@uixSP1w)S20grrpfQXA8!7m=^B}bBfBn<{p>_E4l?!e~sgrv-4`qKY z9?+N8Nq|=H=50`i^WsC9jBX7xH`PzaqLj* zTrTmzdV8nFpA=X^*(((bX&Aqr)iC8z;M3aRmQEEyovX7&`CqI>mRe>MrsJuJQ>@n$ zRy@6Fe0H;5QMJV&hXfZ*qe1?&axb*H&ZcKjDmLRQvw4Kk5icK1TWiQ`ihF+!)jK(w zzd))#yiJh><;k8G-W_dVbG&b!kc|&1?|}G;k$dkLI^MpLe}<20cLT{3QJfEx-b`3j zp+`8RPziViLz;S5`f$Bb%H^h}rL_@HBxo47v)YOWtGDl^Td8ww6lxJ?z5JdWeO3Sq z<&3m4{D!G=wAbi_rnmQxsD*cccO^`pd=cU5YK z072b7MH}FQcL)XQr=hRAr1{R9levj%_HoI{X12@pKA)*^A5-&8Xo39jCO z{3<=;(NSSiz1IbigLY~}Vh+ou6eI6xddZvm>@xSqu}D)DurV!`Z`*KuI_fl4gVx=i zzkf7hvamI2b$%{xSu3gC&taf$ohm%$o!*6d9J`pdV>CU+zlp+(>9mnkrVg!aO(aH> zN8LE*w?ih{xth%8E}*s8cP6i-^fPySNr|@B{)T@bZ#^(oKG%u(cB5?-LDelO7Eh8F zw3oWPC5kp%8crg0!OWnRDhLIr1F7$p+G_Lv`8Mg+z6AVG~Ewl@3mnAuhmSBnnjvZ zpWmpcC97+oGKns(4QFW97d*|J2yN-OJ9=;uu~b5ldNh7dZ|{lBcV~8VfA){Am5^H( zx%Tg3RNA)#wdAiFDH5ibLrt#|btn!c z%9Aq33qi9u7A|N(N&iwzV*a|ZzDr;Oy3a?_nizJhi8sH4Whd%Oj#iWwN#2F~6^f*V zRI0QYIfRZn2d;G7wi~XiVCL>_agTe(%j$PRXsKqPMX^M+dF;rJ8s9QMNCXF`g9O{m zUfOxdttvsq)qj#wze-UOz5Htyfbl0_E4N5cp>iEdV&dH!xRd=AcWPForz#g3XA(K$ z;5+%u)kMV*vI`-<%jm3Ou{kT0ONle%vT@~g0uiuveP?k2SP9$CetrAo__XA`!Zu$| zXTkG|-s)+HYnAqpmtKODWI2HIU}3bMear z1en@iqB-vW=9eKlWP-=l(Gky}z=kMx#zZEwx)2ys{R|IZfE2YdbF$fKr%om6;pgV+ zz3H6Bn#=n1JWxP!vYf#56o7U|=O1qfmI>`8TVaXP5B+_Z8J->&n*j*PDIeAZZu*n8H1DUO(@AX9MGzd&a^`m}kC%2iz(8hG7t4pSBuCn9Zl@ zD2bH5s#iO}eO5!z=LJ{JLAvR&poD*Um&spUcY$(LYDoAnxLBaZM%dAv!OIvX_QrGC zJZDX~%jnAT{vm^q#q9Nv-I2~crCc+~<=_^MVu1lKMFok?&$1yzpoTI28|S0i)vAnV z3?wXJs&AF`$g{WK@o2+AnpC8HE>WzYjb;zl{Wnp{N=&+tpSj7?VRQp(-ElNKyawwV z`o%tk_n<$q8)&;lk50Wn7+FB|7Ww=c_kiVo*3)|^myXC{<`A59v&G=IV4 zhDt1&7QcBt9ni*fSoe`i%#8QL>t%*rJc+tVoHFr&DpgEk2w}T+2X|z5zruN4QO$&f z%G}w-S)pAH)3|m3QBoM+Jig88!RBCq1T8U&_nSn^$RZJL!*ADTGEu$Npot4+u^7i^ zH+)7Me7`s{BlQA`+r&ND9LY1eJcZ;qh*WExR4 zWvzEK^Sx9%|q9>MF_ix6lXWK-)ywF z1Z4tnfM1h-dc;z71XUc;EMz`Yn98Wyn(r8=?)Vy4VgnRFL1)l&za$w?=qxJCIHsny zFlbQw+hlO|?0=fA(>#4_ks|!)3UMxScxg->End~Wg|6?gEaeu={bYrkzuF?r<-pw*2i`Ze9)&cL#{)-vdY8?j{4g(6A^ksCKxQVk(&RGFP5GEo} z<&(IK%qVs~QuvA%;E_CDNNm8f?TGbu%5KF?ESeP_P%j^m^`)Vj3)oOgoo+5*Rn){2 z)i6Wi`*N?HN6D;{R_xtXj6%B9<41lY-mo5Rdv2o1$XP3;#YmNS7z{Wgrn~`sI!31> zDolGiyEaHahcbZZgi>EA zxhCB#v*B06c$9W~7iK$wjb7nD)Is|?nAXko4f>?Wv<+ZDN5f$O6-`&Ive-Q|-3;aP zg$3(Dz2tTa^Zs?1uyoY}F#h!FQ|PPrk?9pNQyi6BC^)3BGk45BNL(<;HcSURjDd?e zCq~`ppn zj$p@A72;|Nv1R0@<}RCN$0^<)NwUdGV-vHOA@}WRAYyX2cjuA^;n9mPwPM(v#?%rl zx--h_@OQryys=4*Z(XrAjjUNMYzxCh?lE3BQVc%m*m$_{Z{NvEG3!oJ4& z{9VFJgG;V1*3_NV0Aol(wJuLs-XT^#AJUwOdvS%CBQ}HG2#zXZnEf(o0-U!E-XB%J z7I|qZ0963d@Rq=!JZ3i_J0{&lmCtn2$Ge*sE&WX*G)Bz)K%l^^qE^aYPOLuBbS(=V z;qd-5Y#rmu5WGJ;jCx~|tcM}c z?Wxv+@aZH~&KAdt4WloNh@{RozaH3RZPHHeo+EFRD~I4s0BxB#|8hd%PxU z=jQ|OzEUehEaYLTq?`_DyV3Q8RHS;S(9#D?>69$ZowCN)X}$pwiAKC1(Ly{csd6`4 zJKNmm_;Udl+HL)fUme+{jA~*y=iItg1vodl>~RW4($bMARzFux9b;o22dR?@-VCJ? z%sx~%!z&}3E%Cu9M\wA$T}VLHp%WO4ILpx%O7)$AvCX&9bMuX5H{VasInX!huX z9%H~zIOvX@{WkfWQ)#2aQ-nrO`}Fc~^BqG@Zc(&pdTUy|L$BeO^+|_~o*e^`4w7FV zVeIgazE}$PoKHfhf)<6*KL$aS%beq*#}5KCYP;*Fjsk{@OHAElI>)E2`STKt)`aOW z0*6UQOvHad8e`nbeE>0A<9i)58)ZOL#d&^w#S z%NR&b(N<(L{UH7j5R`PbYaCDQf5RAqq9chkv{~yj?vCWghKa|}P1G&#mhowdg?vtG zc`J5SeAhxoHkxJyQ(Gy~&fX56)=FoEUU;KVL*EQFsiOVq34FPDGUJd;CTh_$qFxq)v7^zM9<5vv-t{;H%(S}X_QZg&+HZZ zr0<7t&~X1)CI7Oq#)4R>CW?tV`_()GD84LbG+YGeQemqyXLpe!TBi|JW8b?KbE1_j z`llhj2+>!Lq|Elg5Bj@wy+}0J=`^M?0>vA1cLjK~xc&sF z7_saOoZ1}g`!{YF_wHMs;zqwIU~Iib?gs9Md0zCv$Y8TQ?cW{y7sfBHEwy3a_T3D` z^%6s;Ip3f6a|l8<35^KB-5-Q|D``lQWCJ*x-9heOOp>S5FX`DstO7SV7MrShk!XG< z^@Ukkq_TrULOS~~qEic+I9nZPxlkd&&UtFkH||^$K_s|a_#4LE(*UO-J)03pu;{up z39M#eQG31Ta=EG9-->R0SZcl*+CIp)DbAefdT!b_p|WSvBUQ$frk-tQ z+^>{fEy3ZjtkjjurjgMjCRYr&AcqXU7l1_)q)U0-9Mdto>LM-vxiZ{;fenpBzL0>g zh2x<@^<(Gv3nc^+ZI-M4Me4C`Bve?;uX^r!Y`Ph`>514b0BHsAXt%ju_{#_gm3wR45+OGppzajQ z{u0{Qk%ZhSE4c#Ro-(MP>l`Cv_MYsO+T$z64%d?lA3zURtF-uV6B*tr{OzYbtTBuz zBf)R}w>nmwD?q*RR|#IbiV%L^K>d#KysZ4DmFC`%iflf%!bBVYsR+-kU_F-J47McZnK_clic9BnV+-y< z6m$xbkC%vt&zib?hG2g5ND83_7X3ZzOba0^{mkFRBJ{E5QS#A3@I;~C%g}ySC(AcW zJ8)EN2*!9tKZ6pnWj26`V$i%he>qGjlE)@y)<{^*{p%rC=@fbxfg z#-h$=ToHLSc0mSBEJeqZ<;$y+P(`eE)NEYYFhi`oZ0>}y=Co!HXo~ZHK3p|Hn$I@c z3Oq5fr@?YOvsf#ndll1){?4gnK&6oqVWm1W%xvHWU+KERRnF$tGh*s|s?L5&_j@uy zAYL|%z>`a(X0BZAp=NKQUvl>-Q)DI7k)6^aioriQ`%2M^9`XH7KD3@)`R#m#c=hd(_Ap?~gM>a!|020BQ+uTX9DvQ9HElcyu~M088={My7y@6EBE3B_G;tqwnvR`AV_{LcC+B@@yV!g-?5gc}I4J3@=s8GUfq`kY*q+5&#eOej=% zp7ZY5k-JW!ocoGbjNXeKN&H2Tjn5T|(1ASH3enZT1S3&rTdV3)bOQz|0AxlUuOnd; zk>!1PbXHilPQma5BZ5j}3_w(Qs_-bms$uZOW97-jf@|tGI0ZTG zE1zugC&C_NLrNKg)`ezHjBIC`l#$ZW*p$G}xcP~AZy>vkfFTN(vr#d@UP7p9iS{?_u#pIZ&*X?1of1)ZY!q76Hwi7yL;B#oooU zeW<%6DYgJ8T^E^zN(&7y{ug$0DD^1F<82SHu;E{^d94e_E0~X4KIe0C2#|%v7nH!w zHkfT2Ha;?Bfo5Ui_092)TK&DxWbP{O@~8v%WBWY_9x;z1t>dO2$g{dsrgd)qf@?gT zlCCgo(o5()GAWzv!)5zexTk)1{$Vqp$r^?i#3i#_FOfs^fVW)uO=9rw&dae$!n5nV zK_YQ@!8KNaew@#pE708P`>%~hNI0BCsNim9kjYR_TqmyG`RS&wR`8HZqYY<+aMq&D zHu4YL{FP$?bjsT%L`!j_n$2)FmI4E4=|Q?g{7F;I*DAtd^afc_2dyNQy1r^5*PpB~ zABOl4do2@>ZRym$I8Npxm9Ovp19p9B`$AW7XP}b0xiq7{?LTZDPR0HWOcF^Kvpdb( zrz9s&#*vf$k0|1@r?;GxbwapGnd}z9fivNj7FtWW`%Nn4M7F z5WL*L)&*fB1u`YxVj_Ki8xp1YmCdt*-YD)hJvt7t*0BQ=q(Zvo?rDUHl?_It^u5rP z^I(cZ`LsRLEK?5-pIy|pcQV8kQ0N5XFVSo)@tjsNL%?tH&vC~(Ms)4L=&lZ2$z5(1Tfho z5T)oToU{=ahc8{*pC5$pd`vq_IyAcy90-)G2)Nb+vHF#Uv(|2X-apy++)j^Ysgd*M z-vZIbfk*d3hdZ@fOyAxaBX*8tRLhK$vC&JQqEgPl@T2$>L&Xw%N!iRdgF}pY{G1 zlMw3t$8UK{5up$X-4Of?F<9P!jeQEPS8ZqB<+A)Of?jHg-MI#_~q@u?ocY1N!Y#`Hiyn;R=4!EQBmuGJSTWtJ!ci4uo{U6;V` zesN2{pY#hJ6C;-5R~ej$x`MJ(E28vbZza_RvT%?VzK0uV-3a#c6*y935Y9#m|6~>q z3uzb(o@GO#5@)0?*S>-GR45ces%0jNEeO0PfpN6;$X5cW{jNLX1ldto*?8lCy)^7oJg8g715UI6FM zV9;Y!sw{DeHk)N}Wd>42X1K(!@mvewmOXsbPtKg)P`dyl?1dx~ligYD0bTKulvfcJ zDnhE*pER(jEQy>Y@xH57fCydP-6lRU3jgCE?{iZwK6fi&83SX+lyfD{N0Y*SX{TmT z)6JWf44&wgp}5VXRkpARWVF8UCe(}6Unt@7gFV}lFgprf;(26J#g;NCTL84TnMGy4nL zcDLX65o7H9T-{L^in3U5J7L+JfVXS{r}Vmhr2HS{1tl2;dZS%$&0XXsspecfeZgp! z9^3VDUs8^AE14CMCQSPPg1VtA$a~gp{g6R5T00xxdQ{m{be&!h4(&wBt~etO$8b-6 z0%Cw{L@+V$Gy>g34q|}j6N~!c_StIa)yMdA(rtj<2jOXQYJ%;;!S4oOdWKWBj^*3B7a+gRoFA8K8TILN(Zn znh6JfMyHWnZ*|Jc;`R_GN(=ml!3iY*r!onbOAI4A#Q}xf#&ZC*An_KY7Je08|Ii$O z)z@f?hmI6uIiumb#6jj>5~!^%L28_}kyc$-{k^LuWqjQ?Y)6dIlm`;=c)JIS{8^HO zU)O$KNmv8F7ttTQJJ+U<2)4IZwJ5?iR?$x!cs|EnMkk0g7sw33@!8M!i007J+g7SLYbjgyatr+Q*8L^XqWdBAEr z)#c1G1!=F|4m2ki>PiX;k8Gx&)n}>O;QNEw(4PpwxEt`0a#8s;EUoMmh`l*le5g=6 zr_D``K|w+~S_7V-53#)fHAZyOO@kE<7SOWWUXR?)u1b||#Y4ypcFCn%pE_>^xDd!! z1l>7P81&3&2p-xpagSS6yK270!FcZJ2Py_=58vlOJ0po)z9`{Wuui&9@Q@{OR3lgi z+r{Vn<2eT}*;j}?HKD=V=2DD2?lPHZtOJ(1=xkOQ9NHeY^U7I3wSWURaZxlD%by!Q z7NHN(RoMW3lt*q}4(0Xa~ceVvjzgigx zvr!skDLCUjsJ<=Z&lVPJ!_#Qn^_BYY>eIeLFVJw+Ivn%-Iqb!M?ISOonAsDQg>(RM zRkj^N&ZSe(*;?P)97y5FIC3w?UGc#`_@*X}$1cdT*|X=s5*o}1q-G9@i(DoOT5z{Yk4ANZOHod|Q`?|PtsDo~czcL2bp-}e z22hHG^xnNoo{O8w4ggQqiZ1puz57YIOj}u(l>!P}Tb4$N{ClNLPw64BdW&|EvMQ2P zVw1}3dVe~eBE$2B>9WnGmv#MvN+QCx* zPT3E(2B|{`7ZWQ)y|F5TPQNnL<*QjMG#1LJKpT970P@9J&X`HSYCW|ScBSxRjM})n z&JsWC%K9?1nS6qyHxSXT`?>QkNdO+&b-e@E@X*0{gxjvyR}_^{p-?g|{L*}{T&-^A zc(xFttIX~TP3x{uzGa88rQs^`!cdFBBY?9_oCn%njkBuNiz3z~m(F}S@*0y2u?Oc5Nd$fH&VG9@=J!*Yk?PLCsn%z^ z)Hh5!sf=1vYAQBxvrv_F8dq5Qv@(D8&0_9d%W;R@ThI3BIz4 z$usg>b~t=rtA07(Jsgt9%qmR|-LrwiMBPoOyZ*$YzEg6|$G8hTL6`d(Y)}$VJeW&e zi=wofMY(T3hi=&rfcX9{lX>GBFB2?LZrQo?jMEZdRY4b5VS)AGz0<|)xsp?HXVtR& zf`(r{2pK#=D9+Xb=YLl3%h~a!;auIx`jZ| z)+)*hw~9-cZ5(az7ok9&NDPT6E&MlzKo*+~thnO8kOgo*Ry03{L&;ubIS^k_8X<_% zI7#H94*omd8jgc+5AfwMZ9Er}Y!$O%zZe0K4Q;bMTWd=Ytcu5h4$=BV#Q~s>hA&T_T0Q51QrXAG$UB zhmEs{MBCXUkXghdg~Pbxd>j{;=eY1up~BFXNd53NWaxkR1~tO(z-SVr3oAy-ObmiW z@^{>cQC^V;*HY!Q4SR<~R%;mwVI{MI(=IChE zH1o%OU0$OJ_JYD>3gwDE6}}fWH}-UUHNWTa46z=S5DFX2UyleM${zxT43vdoSbqkq zTzX8E$^7S2f8nouQadfdt)oIz^P8s4hHiQ`6iY%=4c=*`F^@%>I`uF4@U~blKyqL? zX)Uahp#$crJ-jve4Pgl;;G6*qzC)pe3uZtYTz|H?$!DKyz_ktF(eop|EwURZCCchh zmY*s0&`giXaBy;gOzxwHedkMs<$$V^%M+de6NCOcJm6<4$Tzo>tCmT#Vy?{aUofM8 z5-50Ze#MFr39~!-ssDF;2M@aWPn=>cSo;5p3;nG?IEbzM@4U)?0MV;|vMyFfM7jSR znERWLp-a}5!z5d8M>Zmp&2XRvW-yItmDn}K?32p)AuQUlC)ST-fuR0~YPTb}{ePqb z0DDR6q@q9KM|ZIg@7WXS)Sjsn8;zP&f=iqR<&?54i7DjYOKsFl&@Hm2NvBw~A)bCe z%bj37acv;xl~(3~68_<4mMU2XWa7Cf;+s;99S>4VWXUP!>+{C#+dqp$HaNNa^ze%8 zD)hy4=2dpl#@rBye?-`aVjF+S^x{Vc-^Dq=onAh4+E`H0`EX4H5(aGsbO%Jk^I^%2 z(7;oFS|uCXi+2Ov<~)~Zw_j%tsl|=d9rau?Qq-l#zrOB31j3Rc{0l|uK8*%maBVsG z#iIxMB>42mxsxYyU|s=FQ;bfnWU14I%_UDT3BjwxHq-blk;4NgYpY)(vH#CCC>k-Q zh|y{PT~!X3HNgf%aTOaBd}K&Zo!u{f6aiBX2&uFwSgYm<*64H6{lJ}-;1#Jr)Cz&# zbson2`564Rj+2#58pDf_V;D&JpD@^wd)2=}JG~oy)v{GvEnvZ{@Vqm$V36YAg**X8hG8>Uj zM~_;(5$jyKyTB~=F)PZ})jInDB!y(FzG0FpEv%t^Yma`L!$27iDlxHMT{E}S;?M3ULH=7bN-r^^LAe-IQH1knd zSpX985MqF5lYR@ePoz`!joc=d=j!77H8#Y0hY+>MyYzf3T>kkjiGt}bSel-k zhKLgD>}^GvH)AjTc*StOX`-lWT`Z~ABF)IW(F=9c?{q8NXaMqnUETOqaj<$3EsNvV)45y)M*=iI!%XWFB9 zKC&!R%2*M@Bp2yp-`repa{-yvd|nUcU6+9GveC8k%`~v{)&fsSL||x5dFhFJH~(J} z$D6kpe5nt+GzA!x-nY+epn%*v-6LfBgH$BKelF!(YE{=aC7*&r~^ zCmi$ce`pFh^X??YwmPhT^A!1@@^Zx|r2haFHDt*hP%by+SJsFW6@v{nn5c{~Mxvy@ zH>}bsN6sxhXN>$%1WiycCz4(Dl zJ=C*|7vXATR-xj%M5*^ypBMNAF!j_a6)Ic5!3kbsvyRAAtV?6Y(P&1@?SW#+f(_hN zJ>I=-vN^*7&a@s_lPu;lm7eIFKjyolqQ%pTKEBHmjw=@DyG4JREF(pbYi$=A+ujrY zpTM9tf$mDD_Y;-NbYS;CxtxsE#x9>C?Av#y!*+$Ialn$_1;uduZ!v|GbvuQw4;ArT zA|QS60l}EueN_XTuaGo#oE(%WTp~91yEso_5NRhsETKi#O#S7h$?=4w ztuOv$1Y$=YO?1x7M1)vyH%c|Gu*(sDG2wm zyem>KN#7c6t*KXu?y(Po3LR?)D$Di7v z);pYs1(e|9u(uH!KG6Y>u6?Y^7&6C$fiJZ_K(DoPa32zO&jFyszSa~1ElE1gfXg)k zU7X^4sF6m7va%6ob-JVs1waWhXJuYYkZxXo ztV>~U-_0fuZ0+=V!n*un;p5@f%S&;Bam<3jmG;e6x3`1$e=r0H__mM7Djhk=Nv1Ux zM@>3I^gkeiF`Xk2MDSyeXHoIH0+I--pt!g?KBz8u=Q{U@k6v`On)og^{l7tije!CH z8*DMMVD9BzrIe=2#31Q+e~R%BlBz=4dsZ)9PU)g{eRVWB^Hiu0Ek4-Jv!adRWDGB^ zv^T6b!LEU&PWkQdPG=$dm&+1wXc98AP7L&TlaWe*8*FoSfgGEDqv{;^&5)`fH|iwkTyyergeJFwp4?v9dFPOnifm4Y-}7x}jRKxA=s5 z0ljRrzMI~})9sv+1Xs=Rp+Ih$WxdO793XY^uUHN+h~t;6v&_2VWH12?J2!;#{^j2f+3y4}Rg3odUp7tLAFr4#p1Wl%HU1#g)78~o zWOkTla5P>t{!!ZlUhTUQHe}6Agj!u)Ln4aCpTCx-{Kgbdj0r3m1yNTX3@`7VB5wL^ z=O+ox9(TS0XBd1wVYMOcX?_~P4M|UEwmWEcWBqCllU7}aSO`)qc{`EVCSb);g2oyR z&3URiS2U`iD)xDPD+m)UMA*OoOMcON`V%Gm`y)7N`FuYYeGn5Gn#))Gv%$gZM^f5* zC}F6L`G0%&`31$1dfHq*!hh_0Y2hR^ll{~`k-I=(zMC!#>v^FN2D9$mDd~tjsfd~;}4lZ@4i|@Gh9s0=}0p0eYOC+$;Et(v2VPIT3 zJ??5_!S$;o|5z4L^?RYL7u?_Gy?@O?PYT0H*TbaI z+4{dKa!ta;xVP6!Po6^~)Y`Y()(-GMAjlg|&EW#RlL73HVxpn#=o%MaH@_GY7?CSS z*P@VHM1zv&4QwLp9C9U{kcCaBX(AqcLa?sB8VU~j^IX)MqtCSEpSv$*1dzy481@OmQ&tc|@tQb%jl!t8+Bo#r4t3;p3+` z_H%JmxpVz-6^x>!6_KBs*T#Su147f2$zQrY(FxRudv!~EF+{`VM^Hn!k#yN<+o>vnzTgj;b?!nNeAa{gkIE zfsONF!@LdE>gvk+;i&#EljRHe2GJjzCBhstfmPC!hWr>w_KJHJbnF?mo33XMDwvtD zS99is(k00qii{r#*#MT)HziOHA3+0Ln`gt=gR3Yh9E-$Emc9p(b61vp+6*sKfpcM3 z;IUGNMZ)1Ivv*eS#9>LUU!MW!hGQvzaCYt&Fa z68~Zo>nDH-#FkjH^(#%-xHpV}eh;V!j#BW}Jr2-jWUX0Q1T8qoCC&8)0ddqn#Rw_! z-~J-ko3BD^sHXr`8Z`JAY3k0=&b=m=-TH<{g$A=k@0_Ikanqo#S#NyIY>)w5v~$^6 zuX*bv(n&uOg5B}grnC5gnCSuKM$a$JaMM+=4Tq#TbZFA^`BP5$%#C|?#^ic_onkXK z0uMKiaOBih$h@J2T=b{o=Q*!$K#BI-%Ct~H_-D{Qv^N$4!@tb%!g0~xem@IAjl)TQ zDQAg3#_Go>xwd7-H(%?)6k3oXI;`3ndHQQrvx%27M(b!cgi1+HTBoE)P%Rg)Ih4-w zFt2wyDpPkRq`u@kH+2eFDI=#SsV-rh$ABP90W9#Tk0|&vS;f>>i*#FNKNcv>GRA@= z6lN#A4GY)45nnS~`HH#28pXex$h$Zy@>Y3#^sz08mJH-!2bk?ub;88T??2=Wj$(?t z*UMHE-ffm|k|lA(8jeQljM+M6Hb=@E4i8i0%J}2fassB(x~FP?P|SD(L#akiDs;*2 zlWU?;A(44NJzH;n4wwlirSt9K;^^{$TGjJMDIu}U;Ah4%pJ`+nwT;JmE_rV}a{ZsR z1`a}C1A_m6_X!d%KbUSC)K3kRlY0TYuX0fuI|mrPY*>=&&#iuYta~y!E!HY_Rz*f* z0gh2%=_!T`Ixc!3fx#%IH1lVg`la3iBQGk7E=(5{m}zGLng^3e6Eo}#;(UKivoy?% zlmgmFMl{x4NX?t^?*G_dLML3BFTD{^5npw>Ut~v3nL?b|9Xe~sbqpDa+p$~ncCK~4 zA9e+_rDX^$4t6qCsq|0pvGt@OOWk6@?Y_sX)BTQUU5J=L5uZndm53OwE;T>DB(t&L z^=R&6bB%XQ9q&N~8q*kmjAlJEy=1 z&+pQYme~i#wSaIl5HkSvx1#yDS`_NCfTi}8(OKgyx}oAy3yobrW7AV_*b)W}gV?;A z6%53BJ2z3Mx249kC#WPfsaVO!sCa8s8Rlq1lTp<_5OzmEYcQ>3T`msjH z^l_NMux5WiUghh#k1pElPs`vQZOl1;-Mr7jXPMLKb03L#SPI`?pb3`EVQVTr=8t$( z>BDHJk{fQPfCR_f!JHK`p58}}crZIyKIAp_2E(b!gP%J^{(B+3sf0n=4}uD5)5ITO zU;v8ZSd<2lSoK!t6Eb4hI*<_C(|5o)3v!6c=tTUoZNNFDERs=PEzs6e^YS*=S*0jS zA#CoutCTPJ{KqSn&#z7tK8)P|cewN_4e!cc=`F2&>hv9hbuwF@9A$}Q#@VralU=k# zN9z2MhSPw)kUYBf5G1elH@|xy>SwR7y}(J-s@(#$Ir^&KQt9cCG^z(z+q?Z+ah&gL zsTvtuU2Rz#hDte8nw%fO+jz%g5sJ0Az1;+jhq zO~6-w4+FtVEfr)-LjHJA;UGV5fOZ_Q=o*n65~(X97C$a+&hU>Q>BXeRrq__klqbzfjj!#-GJNcFJ;bMLqAt%Hu=yR2PsFZ%-V%wbH%|N(Gwm#o;n*`4Oyiux{jA$*?8{Etsuseu(2&e&bZo(S?AJi8! zdZgAE7C$JCW#apm<9|#p(7}gMTw41W{Q5|f-Y3?^z!OAvfJ6iwO?c*IE%HYOw8Lix zNjIq$41VlZ)dG$HIfDu&+2Ci?w~Gm?F9UCr1lTx`mlPA3F~&CJujV*KEFZx4;+4nQ zx}yQcAINgw5FwLh52;72G#<&Z+P5MdmsoQ?awY?6bmYZ`a%{eJWp*DsUHbHd4~Nqu z7!b_K*x6^rIa6m%-1>^2zf?0ZJR>VC9VihH2Sw4Z{NUz^1gq{-tSA$cQY?xPM4+?& zWK+CcG^&w;7gr2(;zEYlo2YV&C|aiP046W3MM5JN0>f3bzsqYfuc~37e{%M8bn`VK zuugh5$sz`ayI7;iTCu+PG{mntzB2INWApTp{!Fk)Fz+j+0(!S~lWAd_vJqdq6^d*j>C1eaxkZ?$dj zbUT|81o&`-&}Oh0T3}GkuVlfmG6z4Ad^5+hW?8FG7%^DD7#^TW7%-*r*7YYAea-z2ujY_;ImALc`cPw; zgbdQHNd9s0kqB~^h4sF?tNU#79k+9+%dOA-_Sl8aI2w1uY6HEnnj>~lop<-7nCnWU z&A0#CNTi3wwKqVZsw_pO8wUvxTMl}k(irVx^Thww_y7C1jB^+_N><&MpM;|}^cIg* zw{B}o>sfWaLX|Sd`hIfDJ+~83{*boPnKTcBFlQoo^`&(ltgy0BO=PEn7qLP#_x&?h z#s?Z<5F&EPJneeg12~$G+&G}I+iZ94dL_N8@elpE@bt4?*njVf<-4yVz`NT)l~;|y zn6BZ?nxjlm4+{4(r(owV?^a=yR%#}Ijf_tM1Zb62%X+9?8R`7^e~i6lR9)Mag&W-6 z-QC@t;BLV+I0Ojp!5xy|?(XjH?(QB4?#^4eb~XBZ$Bqgb@LejF%IS^5?4+GF-< zQ$NTVF!5V-<#>Y+(9hL6>2)H$DlV3D?82Y@o@>jk=0(ADgsO`TX{@Nu_9cKafwG|# z@t9k4iKALGlti$aCT6%TbO=Z#gy@NavQmX9slb=mhbbNkGC zm6S@C*dF|3X`?!;-p$|_(@5n^t6~eg>iR{ANsU6%28XHpKN)B>)Ulhrt)pZin>dTg zAC-81pEy1XA;QYnwKB=6a41cWg()LB>W6k=kZP&n5cYB8ipEc8>`$4gMZ^5$RUOtU zJMndB%$AV!E0b16E5BMwO&c*7OMr75W>_tCAZJPS6}qHENvGc*5?)^i+_KtD26YPU z^SlwBWxhyp|-J9>#PlyU6 zvSo;pp`ii->0F$YSqp3(&Zeh(H^)WqA}eIgDm?yknH-J_T0JxGX(W3~M7OB1PX>1? z@$<#0zCcG4O9EjCg|Gla&MVH0E3bZJ}vo(h0jv{zO584X*E$}J3+KP=amZ=o0Kv6 zza!7KoF)GYNuD{|DP8^jZv9QX{sD)`*T|tV_1x!4_bn=<|927^xZjdLfXIwx<)wN4 zmO=hA#4ptEPkJAuMmW0k->c+5GP(Z$|Dz)eb(y~c$kIHgpBQL7i$}I)ewOMY2<~vD zg>+|sjzx^C7KU+=23%=>!bf%<9`QumT2{e_Rld5n?Y0Sqpi%;M{gH-~yJO+{5uTEf z*uPTGO4p1h$)3QU21g+3X$uTc2^VQW|cKE4>>I?aBE~$H}rG$A#GHiT~ ziag&6y`+tEWQpLPrlOMB=LqVMedm*FWpyfLWt{2dcc({Hvtel8tZd z0mIeRRY4!k?8;TnA5Qk8WxV%szf@)OC2B&W1{K4zRK1CL=bxAY@qcA3e(CGIDxE$x zpSN2gm`R(z6OO z6_|xu9aS~u2d24lV*hyh8PO7FBu8VE00ZG=y-VdJzXrJCg7X2Xsl`yr?6!~nJ@{ik zT$W6D^B?dEc%)Tur<2Wpv@jIONZzktt+aC7#q-@b91)PA{ZhYqT*I*X+f1+P#J{^P zl-4==LfgV1k&yh#d*|*tU<72p%vlde$i#Cr;+U*iq?NDg+nil5%YIUqJNY!J3u;nc zgNxJ!4ccKSh*!M-$#+U}G+GI`3r$PXMXMb2Fb!%k4?@0s`g@G8^=(GpxJTgT&J>^G z6#?FO%r9<5kDVlHwS!77l}{TXf$n+#MD|{kptyO9%jk3bRQ~?nW+X7o7j1{0M=#wH z(ba+Bcr>%!ekO76#_u{B@bNu;^zbyne47glF!5#R`6{}*xw|{4I16DbutB-*crw{B z&7YZUPN~Vt->7~b5n+RL&SLXyP}-1jrXhAvQ55-@QD)6#H`~!uv0yJ)|Q~Zi~`aw))5C zZOJ+_Nnkyj`|N51!Pa_f(3HqXw5o^$mq1SM4djN2zSW>5)8zZv5C@;BU45`jBTmPAk4MeMmD`M zqU8@bDA$=d!E$Q$y&#^7a=epYE}3oNsO0j)=MTTS^-`{v-+!HCymNEA5ZD26d_a1I zhGo!91_hhtpLp~IFr3E`Y?K8#{u;nJ2jUt4Iv%x=>Zzlbzh2_p^AXZ@eyQUJy z+h_WHT7y_Gbh68%T;d>GEZ){dwE_hpraUOF$`aQ7Y;hTzx1f>dXV($si}lsWnDVPR z4Zb8m93^2QA`;C2ys!V|{T3mmmRz>dO$6vd_RBn8i3h;g{)HeBa{oIF(1${@NerT_ z_n}!=A@1@I?q>f*^195|#@(r)XrPP)yp9D;Fle&?hOA>VAe+7WHvX)t@h_|Q56{(bGvNp9kQtlrlyg{P*fr;lgz5eE&GfX^G9*0{VgSq{k0QaPPW#ai3d zR^Q|Oi0$caC8W5>G1KmTM-GG>erUwpv*52H3}B|r%B)D{4xbfHmCs9`%3#D_ z8opNo^KqS1%r2<*G0@a%K%lhEKqaR~sxpfPFkUJrG=V1)d zbW!lfv2H`-tV^n0AdM3AOW{L-;?eBSXI+4Uvbe;0aPD6`yxo2BMzlQl zXm`~Vl`^Sd6R5Hhv`xR}qZs`jzv64RydleJIq3*F$7TUILyC1v&(;)WJJzGu|2VF< zW5Y%VoKtxPd}X)X0p;4GtYg}pc9Ft}kwy3FuV`dqNHTzYMt4Ja=|uz+G`1U|{r;Ed z`ry^lXZ|14bpl|z?m3B0eR}OwL8Wl8?0;ZNY6cIE`ESp4Gwe)c3@@)KJ&9lvdoo;n zL4BvMEEdvP4rzi61cu zMbczRtlIhT5x+5eefNhqe@+J+-376!$rnT7+M+(t&Zp#zM1P?C3OB#^8wl7-`wSW+ z{nYl+4YkE`1-yYLUY?~g4JC=8aUxSAGVlxg_3r(z$Jjys=EY0qZuw-MLTz&2QM4N{DitMvbpDNEOF(Ku%f{i4S$kJieS_a`aRV;1H2-xln!KRG+u91$4T zbj^1M&uONmrD6AE+6CBpl3W$cixKTt-@^PL&f7~9lSF=1VmsbGMeVVFdVk_*WRSb7 z9+KqiHCCSO@Ab5pI28DGRxgWLVs+sf$Y&Gk2NLYk2Ha6KhNUc&oM(?#TQY#`HhpSH zh`bMFG_1BrV-s6^jo8=1^|1yG@xvOJb04d8ysl6FU*M;k-v>wtOnIqAsnd?k{;_R> zcR7-|+tbm*IsYpP-%b4tDYE~YeezxYU+mLpJMJ&`xd-wW`((rd8QTEZ!iGXjOKwmU73oPs2%NlfplZ7HJjn>T(1LB{U=b%9ZFK)7HQU~yDE-;<3J zB(%N64f@Sq_%5$EDpWLLA!-m+$cf1QI1pt{Xor6*G&k6~`P%PZu6D}`IFrMFyr#v5 z$z|FBA)lg~T0)la1X`VOU*n2PFb4{J_KNt2u$@ERBIMz$dt5PC7!SDcm&u@g;lYZHGG?cgQlFt5D$8R47P?ONGH;LBT1}b+f@S`g` zkcQbzKf$j<@NX0-zrt+NPT}{5rU~tUbr}4CtLN`_=d@jU+$k0WU%R%yHvO3!(keTJ zyhegd0^*Mb%|fhczeo%sTD1jC3_0^{-}r6hV)qK}Q?#?XntbOoyKd82T%s>#X89YrTW|ZWb=3@NC^<42#O&4vKhpKNg|_GO5f3TMzmfh zgCg^=juH@-(gMc7RDMB9gYxb&^&9noMyjY6FQJ$4%YJm8>UcEYiT^up$@cFNkE4=f2mn|-_E zEbJH;0Sg*gT6NnoKN`C0?h?CYYC-I(BiK)icF@cxihc6RU!9pxwFD!8T2Ou+>x`6} zYcSQ50qD2M67u9!Ze)g=0ky?P=J*cktfTrwx_^Xj$DRhW@zq2%rZMA4bM{yejd}?` z1p-%WDr1H7*>xX^#JX7<7A?<@GvPEw&{5xW(Txq4Q55`Y+xNjQsw0KMvDm7FUH|biWmyX&5$plJV`|iq_ zTKYh@#G)M~b)h`_NjXMd|H#EV9_4*3hIx*JNaz-22YZgktNG$aIlBr*F)Wkf}wx? z-D7!c`v&&)!?tPX!-(df^NTL!y9l&!=@lbd)zpP_8ciW7$=HEJqI;SiZkwbzTZd2_ z&-qC*cGP}EdPKp@W+x&GRI&5$GB5mi8REGMQrLq&kCUACJ8(w?Z`mXgoh*wzfssz584TKSrqZf} zHC1hWsV47kBDKiZ)cxY+NX~a2eV*=t_kbxxe{MX_&`x{%!l!c3wDoubxPqch4&u`4 z19Ju)Rnw>uTr(dzi_YywgQiO?IoiRUME&xj+w)NxTC_?tcc(+he#Q7{{Le3pBE)ss z;(sT%`XPaUkR%EQ7H*m08D_?Cy(d0OV($%mk3x=d@{B=VR7+Hll0ZX6d8kY;^n==s1_Z#iSKgeV}&AtOgE0=_~z0Hy&G0u!Eq;P*$uzt;m6h<50 zLxIp_99F*XnElL)FU9xG3l<}kC8-=DaqAs9slYNyIWEH7|2?FR+X`u?GP9v=>4R3$ z;P;6TyYFSpX!2cw{#q*vFA*<~=*-BUCNud}l!*yR@U-x#-0xo0o>Mc`eJ5)YmLv5s zqgeWUr5rcb&1(j4dOmpDOJ3mDZN2MSM77Xm3mg&%pe5aIziZ*EWkGmf?!6Cxa z%<~4x2T(|Dv4?F05H0`4`3BZvZ|657-?)-H9HV-at^(w@4;Oyko#kD1y&6@1J*k{+ zIC%OTe6KTWIU-<=Pz+O$xVnH*5)Nj6CBp`E99;)w8eBS#B;;v8$NL7tPJJ9yr7NS& zVaEW5syZu%JG-C0|6xzyp$J=>hAqlgsc*`OHI>Ql`z+|rpk7E{^s%@W5SK0$Fj}B$ z_pv&xe9rcJg=q4D2wGpV@MyPcckO~g_3QE+5@lG5g|g{o?!sk8+$ppxH+l4MM^v5o zZR5l1)P2PO;f8qc31oqiO=xiq#Ng8GZE9z=oedwMCinR?Ih0}z5D>0t zX68bHzC4IJqdGHuPWkWXJa8$o5G^k38(IMA!htTaoPOGIr%o?Yv>M$ftkUoPgd=^Nsy)O1dI^^ek zd+3w@F+q)Zt&JuK?KDT&XQYbI19z}|2hKz(e1%oExeywxMOxQxc4H-zYkf#&JCo0m zAdDGlB4m1j0`)F_5dk5O_2~-OEp;XX@!l>HIDTxEFonj9_zc&HUn>^LW!(yhRrJle zhslv}95OJ}yup==K>MgB9foVc6>4w(u$r)*RsW58vKjyQB1ln;2wa%Y(3IFM<2>Q`FTuNECz(c`1vLDW!=$s>}i_#~dWw zfrq^&0m&9aZS55k!AdSCqf%4|OyFI;eV{ikg!)e5c-|9qVUbyPvG~O#hye+=4-XmN zP+fdnGb~*v-33CBPfu|bAFwkS2Ad3seCTSN%5CL3+K(`o_;HAIlC|_g?=S-&S}1q& zf^J6KO%mUNsN$nIgT)}p1zHE~)cnAb%4$v$ByfySBD@Q!;5+>XIMbB$R|YaJrdNk> zH4=NVJK(68D5mPF85NGYdFp?Y{~)rWf7vxBazFZ_*M3etGDr@Q!4nD+$<*%GbAVZ( z?`DE{c-n<;0>4Yj-M4BU#dYr?-^Jy{(2SbIZc3}AWm{zh#qH}FKd8<>fV6=4uCpvVE=U z&SqWlKP)(8LG-kz;I*}waCglJD|O)u4>1sU=}e8T-!-O`6E%yHEMs#^{$M_h4R!Ed zsk{-wdT2x%-7x>~wQeRf@STm{?m=+&XNQs&$6@TDy~4=vn+KnsKE?(0vR-C)2uquU z^-=SZO~U>ZS9RQ}q+S`_NP)cW6)+;h{3Ye)azkCKSq_Vz+xoJMK9>G>h5~eBo$gsA z5m>Z*OXR4atay{K;JnaY@?XdhtwCNyyY>7EullhJl%DTS1;#0l{y_niD9E+kmDzBQ zk(B$yxiz^2GJVN@XA(8Jk}ie`4j@gF`;*Icwt9M4fC1#Aa&bmLTN zu`e7jo1cpCM#5R7Wsf&C+y+5N{=!HGOvY1P-^?)bdLw;CQK?m21M021FKS$y=Y`VY3F zA3-g8>5bmirW$P6rbU@^1-T))$PLT3$t7#ubP5^4e5!;)d*GGsr`K;`Obz+F+Yrr| z?8o4}gfG4+&E%ohC1fqbRC8sjgTMRL-mBPpswOt;Ajng#Q<|F~;R;~)ns#Cf+ftRQ z^c$VBPI}rMyyTp>7NOPId+~z5YF^iVyq?kWR5O07J!>Q?l6WVIhh$&}Ms_>#LnnPD zNLGR-&fOk`e5*A?gqvQ`_ZaI6gk@4^55`vYTrx;SU9BHREqUvR;W?jR6WO(45lO0b z#=fk4cvpP&Wjr9p=S_v6y4f#T`R>86sz@B*Ypvd$G?~qF*z9;fatAUHC8dZ{~RMS7KkD)?S*jSE&GIRK6S-5fGF95>p4{E zY0?TwqA-b~YaQ81myFuzMY_Rt?21|;LOi(x_L2BO2s9)Q-Rh#*L&GBVj-?p&B9k@q zUX{F|Jr=_m*K>0^SMpQ0N5zsXnbAK|xjosI<9WBq>wErsO|Il^E#BD|!*{V@*}QMrw(Usc+p%YiwcA+(S~<+%a)69f!`gU}2d_Bmj~t)~cIqg3NL2L(|H^S^ZORB$4sL_! zFLvRwAmnaE$)r!4sdhKgr=#;g>Bp0MH)_n3&SzBr5W>M;C9yDatv>)Gm7+h2NL|Z( z>a?Ej!Y6~KVuEBB?%>4ES#%MFfe)&xo>bm51_xd#;8#GX01g-Z_}r1nu~F2EBBb!M z&FOPY`>y|DuLqJT&N?~yLS)i5@+z?o$ zu>0%Td;D?Bi&F2vR+Unn8;6mX=%>;7`)A2lBrEQPovn=PshvRS6*fYHC)4QGQ}Av` z^8>d>BRYFT#7={Z3X+L|3|oS;4KS{k2|q_~Piv3^ez_|S5Ie@k&6M3hG@{1qu(k~7 zvF)t-oBK`Q*{yC&@&wv*w$!E4pajV%f-Hw{MZTEH3o zxQxFq=z!a=0P(Op)? z=m4gi`(aKxg(v1~4!&+5Dziv4Q8>7%H>mWFa!Wo)cF*5xwt56AMyf?w)<9BXipQ6C;gSiByV&9{rt_1Ccl;OxivF z)P~3+!bADUejFA-J5XfN)%u)mjSj}DQ!;UDXT+}3jkiXI}Q)Z+7?EFF}^OK^ngwA{)GLF~aQmL4W zI=)XK%^#N2!dzWEZpooo^w96v1kXHvYFNHZe3;r}El@$ljc^~0k{-i$A(?bAa@YL; zdBpE9joU<_bOxp1G9s0{AO^n!h?$?~_EsIP>ZdYs9x6-O@ZyKKzIrIrG(X6H{ z@VpV#IM&26)HqUq4m+uFA@eA?Pet&i4640aKam81OTkL1wA;i6K6x+Sy%ryQt491SpWX>5 ze)F@mf}(jtam;!e^)O6pRqg6&rFb?Q9*paf26CIi>1K8sdw!+-X9Ld?SGmS=j1*F- z%j@*C>16PbWkO=1vok&`yvM-3!dn*QB}b`HE0tP*J)U0x;_nr zA{~Dup;Qq_PmCTADX$z*?&KJZqNEs3i(oDgHnenLzjN}kpA^!os67X5lfbauSl0Tf z6m}hf67g+2(OR)2rd`I{t4C>)!V{xH3TarWj=xYy1UO%FzQDN@Dc0CLmepi#Tr$O5 zp*<{}Avr`fST(KvQ|JD*T!@fCw*|8rq*OQ9K#6&B2Eq=jFrGg#WsOSSY4!g}@1?A- zRG5E`&Z&ct)#>MH_2UEyErEM>o$3)ur)jejr!^AOk93QNgK$t>-`8s zOe?0KDEWwH4ytV${{XFBGorx{-x_xIQbjo4R#!SxdW|11IXY4hrGfez^aKkLN{v)I z_V^c?-9lnFOVgY9+g2wKhc9d^+dIbFt^_o4O&5$RL0(R|*{Z{tVM~LqcBpj}r_%k5 zU^Jp}78=UH8CZZp_B=B!UrJ--m)LjzhMdlG&L%;n+ZnP!48|g|q#Y z4_6j1Z$jo-dv{LYsQSmjV`mOELHI>KL^Jtk4H~UXycteFL zufXK^9#i!eEJdQ(G^W+5W^c^#c#TfRe4t@ZxlIj+8aH*W{lMi_v-3MGoWq~f(RBRR zdKx3E+4s2S2qoZR{_CI_4PD5YGT!`XD#OXG_iH1wQqa=ltiymrII8dn2R>`^Mw_=7 zAgW~H2&9(G?Q5|ycn0wvdkp3j*ZK6=^W}phf>ux4oZyEik_y;e^iJ1?+*^uAt=-&> z|LzL26{Wp@@T*BE&#v-xdWL*m&V^YA+6`nHe~(fM-~LL(G={q}=BxWstnM{K?_RX9D1>vMWPWeMk|73)i$__W(q z;!u$KJZRG|0GndsbGwf~lY3OgrQ4WN8!1e4-j7(je>?lS*uZ<-5_DCdus~ZA zC$hXt4@!3$CR4?MHZ^6uxkkGUC0 zgnD62skYhhnN>#WGodfRMBpIccDLrYU%JI-XeiCUlv=NCwtFb|?@qqhb!PRxm*s^j z=inKMG` zDV8%ZXy_rC4g=1%m}8=`xH>=sD&y>9(d@OLK%-P7TFVEt*HQ~t=BfQ9pGor>yUQ#_ zTDRUkW!TPn5L{{KH9=q2-9^9Q=BhFr%uUYLUe6?1e>bfMZ>p5FY|iwxw;0j~d^6}! z>b0WwD-y?F=M;6HrCcdRdQ@+Ha@9^e2-&*YmwzqGfPs?(Z{<6UG0ds;-7dZYk>BO- za?TZ=Qg*c!ks)}|f)gw-&F5dFk`Fhl8}WgGQ(K0gN?VQ2wn-xX;E7SM^bcG2qM*HvCtL^YdcXJ{jxIm<=q9VQc)A^ zthzw!^Q_}XD`YVpv$vdqy#%dJC0x!#hMBwo+Fyi~ILo7*WI3=4cBN87e2J5#^@jio zXO9`2IPqaPn!h#=-(qVdwn}R{ZeCh|*_p*D*3Mk~asAvdTdyiP){nD@eaPUeFDG4l zpgy@83f=U9(cx!a4QxZBgbu~`zlTu#_d;bxMjodC3!iHL0Fncd>cqgMSxV^;d}1}b z;k@CZ%~}W5EeSo=mLcRL6~=my_1tz8g}f}9(j^DJLUq9Eq;=*K@Yzpdsut=#-aTaj zk@Yad1)6idn_|i>Y5tIncJoMQ-wqn@rnZ%9Hd23F4I^1rUG+6k0=)0US`y+SbFosN z76E_lT%S`FYBt{Fc|Ldrx~h4J*^>MZ^CM*Yq2an!DO0=8l3Lo_(^Y`Ii@8E~uN46K zHNKwT=CalE78K1HYmRbtXm21$G0Ao9-1KZVzuR+d=p(EmGLPcfW_A~vHu)m#B? z;AljlqJ_s|@SH~vtbf7yH5HOHnt-KND|8+ld;80ymWl3%UE}dq>aQqy7@@_RT6n|D z5}OS_B;J$P-0gQuFa#?Aow+(TPpz-iw%K~176*M2>|wrm#Tq;Q{DOmla3(6+PD^%K ziw`cvEdtUxf0mE4q)d{tqK?7erG|1Dpj6ecgZzB`eHdOjkCau&RR`cxO_ zWuW=yr@R)z&A3nptYeEL9Ph$wK@rFz$-4qZP4G>Fu~iL2I}JRU7|ma5^ip9`Z??c6fxZL?bWto|&ATA)`c z$fc4`Nu{lg6?#k}2IqMl#NtT)USYvSF@W>JEP|&P1LfEQELNo#HJovg@Vo^O5iJ8} zoU4C$@LvbK*BEd^zwr~$OFBa@T20|#Ii^;nw)iX_b~Fjz?ckh)TL+ot7n`8y;NNCA zo?eJ_=55$+U&%vUHo!%bJw(8596X7i^jidOcyTgD;jMAQQiLm+{Zir^3;1VD@V#%z zX)1o4zF9mbbW^Nw(#u2IO2h7s`T!z{KZs8Da@44tVcd1d8HAqMX!eTcTCB!s2A?HP zI`ym5y}rJORL)EPF({Q3cL4w^_|LH9+G*f77YEK{?Xd7WM4y~<+$=Wo=+rosntSAgdQ3&0GsfP>o4 z);Xw!N{euhK{eOzg%D~`Hr}o5(Uw`AZ`*v;QvI<`Y~kG#%;Kfm-G~0RxCKu@P9#Ud z1u#Pl7}ApG9KDe=pb)?OeGOX*VdEGi&qBI8sKKIZ;DNC7w6zT8u`K7fk%f`KX zn3PG(47NNzDC+ND*_TnHrrJEmK9`059Z>R5#pD+9?Yr#8Hl}fN^uQ2eK!=}{CFBu1)6yg=xy%^1Rcu)9 zs_i~QyJ>By>k4bb<-}Pv4?LRTS967sD6+I)q6vtXpLhq<F7zhq_2E{Kdz*qoiSsBGWTX6}zuA9-vp#&=2- z@`5Pi6~Tz|(~T)z#`f{GJLN3REzvmgz)(_|y*cxT%@nLVeB6EqKQ5I2E;@;kk!61m zEUS0X+GNc(ZLTALA~tFgk>C|bAiQE**s(Y{ax>qIKG+;67D5%g(9=#$(gk&!b(6WqUdQ+^Y6#_V zT0f+xIBPk~`#JiEf@daeivo}c!8S1IVT2d`WW zx^XKwM6wyoUqz)-z^B!!AzyEEkL9#k+Hw(;{`Zk~UXjplgXCV3QeMQ~{xE2qBFrMa zltigK4>JCfBo?GybL7q)##XhVl)aD4Y4p}%nVe`8!#`J#Lmm6{c-uZ%eie=Y!K1VA zSc2ueWLEWChUJXP7~1wtD0MLdicrBas! zOLVi3XkBjMXNi`Uepo&oDPNy+Wwu&d4B<~om&!FD_gyU+KUW+1E_??qFQ}Xe5gUT)y;x05QjDN%Y^P6kSND84zauaCsl2cv3?s4Bj zXZ);rS`TCtkl*qLanRm9LM(S$`N5W6?qh=@VoSQ0=%ghO9kxxWNb6+9U3H`JNyEku zzCf+0(l}zOEd9RRFHzWoN``ghx5!O`z-46)^AE!upqI<3QzWq{7hWyHwO%$X%igqC zA;3pXhS836MD}Dsqa?WziO6;MkORKUhxJ?qS`20&Zn2q8cRr*cX`+~Tda}Cl0>((3 zqP&@$p1QPlLfP(hIYvD&y~d8Z)a>>LR_Q?)=umfRXQKEGJOS1Yy4sCBo-5#N^To*z zG!n%O0qx?#!uMWfGoo84L*t7)@8;He(L5R}f(t)U;bpiYnGo zdNdVTT3*+QV@fZvsy)h$ej1Q=)HrpIh{Nn2Ru5y_&speX`UFBeXGrOK6xv@o1(cez z=DS#^>@FAG68H+q{RNTCyh?A;Z}Vr%oaaKs&eH%6gqH;-v=EaMKvPq zofee31X6J{9xo0zk9L!U%Pq$Q_>s6ja|wavV(<3+Bmk!!yR2g;;!_l`OKQ~$lNbD+ z$6btqtAjkIga5(s4oBnQ+D9hB&bJE$PGg^^IShj?A>8}rp*mI#_0ROo|0(x*;X*&G zd0s4em|M-B|5ARn5#?`{PoPgW$7z#GXEl}KbsP}&a8nVtIK0lYotW__4ntvLc{b)P zc=^RGYaQLI^R&pceezhr^U$u>dud0$K>NYLSTW1t!{N-LBGGM8=G}<@uK5EK(9qCM zi$!o(-09?ofjj$a7aCN4MCH1|^^?;M~-eQ!i?z+YhYSb}P6%Y^b3mOCk9Y5&162 z_0$F~d>8O@r(mBGc7arH8C#WToJc24gU4DI@*_16ph0^Ljc4Y`v~tm`AC7I?$P0o@ z_r02X;nzof5p$*Ag2--bohs9E&lEhkP|@t_^|Nz1LH${m!=^Wt1S7{tB^))eIt!69onwLc`h?pnt7gG}f0$3jbF zGQcz*#=9Vo`Cr>vm*k(T6wx|aJR*Y}L=OarIW)dz?f2m+*@>TC z=nlja85c*EqrvwYi1R|>3J{J|C7&AaKrqMpWgY(K>I2qd*E_~v`uO{&Trpg_e_Nmb ztX3ijP!dbb!{r|uL=b5+F#lbm{ihXd>yOI2C8{#=kL~&2bYK9fpaI%l(J9kz{rrlr(DTPAN&~fZl%}7HW>*oP`a?gy4bOa!QM^z{M}h#0?Elj#pty!^ z*&ZZ)#Uqjhbc@Wn%+R*d7*ohdOz%?G;bFxI^Dp+{I6~%!8V>7}I5U}eJqE(y(VId_ zk{rRtXP22;flDfr=tC}KU7(Ocloa-vuNRND+4}Y54umNN;nw9^yj`jb>W;1AI^B+^xq)NS>Bl)w>~AQdnwsfZS0jS4CNY+G@L7PKt z#I*oYmtDFKm0V_&$^m1}K%!k=7kJq07zwu4x5b^DalQ~kgo=m>t>TUz%!d>qHy30; zG%5bw_CAL@cUajwXa5TwqvG8rmFq`NU$`s}?ZUjsF&|B5Usp;7P$+~GGG(_+Xg3t7 z<2L{MQu7c0R=*;nBpdre#1HCT!j;WcX)t|Z#dFf&d{m|HvKhWAk1yv3JU9Qk>J&Rr^T)k(# z)mkHM+k4Bb%Pz(DA)d1d6xz*gYmeI(o>P6!St)3QjGyHmGeNI>7TZ}9=o?(5@mtSZ zaev9^{Isa#CUe}Ex`*4_`xTU%H)m1Q@^7eWz8B<+`@zQHL7UE>873~WHBGik5X%i@ zJ}DA#lGY?v=1MiKkD3)#;lBEQ_NPhE4gk6wq;MiW<=E_7O~1{(>h9Xx;z4#-Ks7{eW#G+pi|oS(xsFHWggwZ*i)Ia<;EW7Z6~4Q$Yc(MblNqam?Nt z(f8TFI8Rj0=t_Nlu9?-=Z!r41D84G1oB_QOO4bsQCCMRx@=_!>d+haGJK_P%QAwF8 zj#ie7&k&=LO+FqFV0_zc-1|)hPi5h-WW}W`;1EjbT4Wl(v4J4hjXw{=5KT9Tq%>3J z-rO!&=Q*5N=kelNlC;ptkPEaqQcL)ggWG)Tj+<~kx*f%O(deKurB?A9;9@AA(fChw zn8vo;X5U)bY=PMQ?H5Q?N&KSzby-i&pscuO!ekDfxnj|UFJ(+axMB(g()`mCRX9Fd zG^|joIo$ZKWi`FRA@$H>q!cMWOu2%#dZAr&ku$mwRsS7zqND&6?^jQzZY{fo6pII!Tout|CdEZV+B+I6VrC+&pV-T-!FsS~XZ}Ss_!ukKZ-G&vue1;Svs6|LvzAsqk7R(8Qhr|&d!YxI zNm|SS4NgV=XJE%@x;BPs63dmxeo(NK% zgFHV?<%)}j!K=-i(23-V|AAgTcM&oiM=Wo)!tD-ko5Y>AQ#dUCG1Y~Ys?pQ?w9hDI zz7-;UwKfVSsPGu~o+*Q0^U%)cwrsu@ zaM~Sw?)dRibSXu7))P|5A@_{|e@WRg5LBfDP`-RNFFF!9gw?9-`*z@%rAlqHBVCY{4qeK^(< zXAp4c1(cz?$JqI{U>9^b<9hLnU6$cK8+c0jPtj+Je{+Rjxv3hZEY81sXee91;O&me z(RW8G##A=Z%p4i(MT3!Lr^7}5Xd0gV`YtgAX!LVw3$IR`h)Qv6@F!}f;HNvz*uT33 z7CuMXXmfr4Fp1~rY<1}2^h5d;mBCZ#q>l!@8O#fg)51C~Hb{DY6^o&uutUy`aJ?>E zn7Z6>2XnIaOxSvci!}zU3`Udh1m=ZoJNZmYa5Z$`y2a&+86d050@mNv59$$Nn26R3 zXQ(E=_YS$nOS4(9`jz<(x!WV4%8374rvkJBxVR$?_w-E`{i_6_R+ZM=*8mO}RP!Oi zEdvui2AmZ!OTKU5{=v#QkvvQEziT|`qWNRaH`EGH{)p-a=ZTYZ|A_*lY#I~NaFqKjsTmYZ0W z9Qd>x_s$JMG=o}ux|D?g6|4lMy?!-@i^-tG!GENRCa97~>IY?lIT#wfMW^2ys7M$> zX**}BT!BzD&`v2&e44S=nOo5YB(le;V z$?V=NU+@3v>#U;U+SY9y+ylW~gS)%CyOZEhxVyUr2o~HSxC96;L4v!xySvMs+54P* z*IKRZ!wU~kjiRdNm}B&>_x^`E0!z0Tf)scPTE(kHPU-FP=ObYHJpH(cLugAa4?DCw zCNaw}I1<{|kR4v1vPGo4Yq~pAi7GQ194XrA7hbD1VEJ6km^t(WK!EehFmoA`@i6bW z(E^i2LDw;Jf)ufk&?KMP75DYkLeSHo*jTHEkSYrJCe#s%SVBXiD-1+|)5l^fTB|ji z^cUVIc3x@ig<}LO|5^tFh9N@eUH2s`5cI}XqWoZ9kFTT*89_K7is-m~>(DltRC`aV zBaP!Z`j`_aL%5njA`&+!qE&F3fA<4yvvY`yYDPgxYGX@L9i6(#FCrAaiA{=}mhuu) z#mI*J-mzzTn{-xTaVwZr#%w`j7I&(r)#`pcjgQj^gdMT5!2Wz03nyu&bu+y^DNC_# zL?LCF4t&y|lmCq^Qff>MYLF?4h&A$iW5!JO+54^{pTH+OziF{(<~D^0M z-St`8&KZ}HK5Jhg98_itSYj}6{^KtF4yF2zm#^{bhY{d}$&xbo$2lerX+o=+u5iA~ z$(=n9n4J(iFtVkP!R1Ou&t778Ymu?N0?`5@InTNZrpVG}8VcJ!eh%3P{%QY#bdqso z=-l7iSY2YmERzcE2|umR?(s(|3xZThZ}<0-oWgD|oLA9d3;a)4v$M+Rc8zP?xG{&> zUr+UGLCUS0@~+q%ic_d$hU?LMks;rc_ye|1Q!Wz58C>(M#*jZeBLIVgzP*&GPDkAt*EVS3$4-K0)yN3V&nuuDW(iY5L{zHn zaOGi({rv^^B@6m7<*UTX#j&OE*MXhlC+P4@!;TP zsl4zTy^@a8yT`NWUlyEfx~R~JejC3O^09{n%lWgyd9ho)Z{;xHvc>8ZE?yFfm`ks2 zuE_4~oXqiw6UY!-wS(5LiC!Clz(#2u`37DESo%kx;Ih*ExT@k^2dq>EH&*6a%M8fP zVz!{g?SwSiPERDn#h_v++}hFtGv#X++j}!RfQGV5D)Ug>ugh95Wvo?n>0c~Dpx%$2 zVmh^gUf~kQ=$uGF?!s)+<}psLnasu#gBjec1l*3n?+JLe=}LP3Ie5eM!@2dIK?5ut zq5`CW0wgQWJ$fL7)mP&42S@i8cyVZ#-v zuH5t=Yd>YfOT{4nXw0~wXJWk&wF`~9H80)+fXbEODNYP7^PY0?l43ZoL9|jlwQO$= zl{9ERL4HK{q5+Ilu-<||^qMihvHakjpECJ;IXPF4vY_%UPU{mWJ_fz(XfJ_Jy~s->&<|0=AiJO=Gei-nkDiY$dBT0O2ECKR<+t*!^pBS| zkHzK*_d)Ly&_+*TFxtzDkF{4h@uhwkTd_7(D!OmcYMdg7%L*A5{~mjA5R!r85*wl) z1{EBfwFL1v14kfo(05faB=wD}YehSg=S`eLGT1djo5?J#daM#SCX_w|J%lE}Z6L$e z_}z$vSRl=Yb~**(Xk;DAkBGbbAVqTw2chaw_T!xR6F_y1p)kGcG~-poSKogR4RjZ1 zLb_NG5}ikweP&dt{*D?>z=!;03NWNJ{XFHiMDA+S3A#rCgRNV(w}0pTc>%uPulzT0 zO#QI;p6UUdRlE_M;p+D86t@Gme??B~X7-H%IBlB^`cuWD$iwfT*)(ki<_j1jqAgCq zI2j4*^5&4``Ftm&;c+*e5a zKvc#`*zVEn&PrNdD++K8bzt8RaAaOXRUp`HM+tIjr5>$Qd4fm~%QBK)5R;U}XJ2>C z^Y?-I7vq=8FX$72Q_GI$W-vss&#n6nw;Crul*Jr1C`gpxlEk z4hTpQo4eYoye1y{zO|5guYaA_Fql-y9lC>z4g`D&lV2SJINdWAXmp)#Z30~d3R#S@?9v%)j828 zu*nh`f0`4YXC_5*{)^qCQ>!J?IrYMKPM54&@f)y!U02?&6~GE(&Ymrj9N}{>+cwlUuAX-akIJta zgkDDr4jrfr2$VmB8EOTYhRMS79dbxNJ^#>=l(S(sM_7;lLYyH4M=y4AOlXW_1pFea zndy~jdBS4Hhe_*g5B;E*+8e!k{R)g&TYb$msqiVIVzQ+=m~B4q90F4$4P9-v0=)FD zioE*g06l~FQNH&=X5=GTW9MXM>1zu5RW=zW&5HAI_V+-r`2a zbO}r!VhGu*Exx$G@3{>mP`YIirx*dV#H7tf=NIl9sRZk;nm{p26Z7c3;mIkSbA5=} z9Jc1Kf{ODVry9*8MKdFBm1N@PQz%~TW;xstZ$eDQ2n+$=70bn__Xi^&-m^pG_<$pQ z)x}bPY0`0fJg^}j7YhjOXQkM^hF(?IKCOdEHwK~P%7L^Xlihh&KmCN!;pM_PT^t~j z5tV4b+Q#q}=(I~L+AJOQlvC+7ykeC9b$FRef)>F(VBlz~n6nX-Kq|ZnjiC!#n|bu) zL!!!vs=~dC=FwV5Ld&YBsPEr8;i}fm<}TkF_B$YX zN=Tn9%;MIHdmayloH#4-|JdyNm@?CNS%>I#@T0!dp}m5efDNivvsAIWjE6I~PII@$ zbcjl&KuWDbhu!meela$o?HZNhZyNXcTg0y>r#+GK4FCxkjfYxya)sh%D{5z5z$xC( zC#(~@Sr7d-8+8>mPv2cEA*&Y_Zg-niv_l9RNM(If8Xa_*CFH7X$2MTtFGp0|Y9%6p#cqB zzm$DOdWR_lIevs3EOt!wLd#&Hqax$_k&wj9a)96#E#aG0{kHq#Fn-i|-dK`+TLzPx z{JXF>FAliLTdJkj!@m6LWJgFvX?!N(WY$`|&Aqu2wNkA1e~!R(JbJd+Ngh;P<0FBa zbKo#n%G_ZVMEK{ITti*km0%=j(Eo%g{%3U7U%v$?5`x)1AiMe3 z;*)JF$Vij@?S1->qvU`7?RjFr#EV4i_+NZ?Y%>g?iQa5FFGEW`^JufH>Glp`a`rMAGD(kOFJF9t@g zN@lLQjx$QoT`GP{^Y#vOJM^Z)HlX`45qRM76 zERmX0K<75YA7k}Og*cMR?ub#kJbr*kLg8p-{H>T7*YzL)i;k7(KOdp06!2&hq#{dW8GaEQd4ggf>=vVM(8f@YO2{GzIdfNB>VGRfwyn&v8cm`wNJ|0vjA4TJ-ffSg!W%O_qM;J2D3BJ&E3J6qs6`daTlc zTH^dg@ls%>TCpK-*LNy>JBeYHaKEo%0B>jmbn}EbRw~7j-GA{0vk_SW^HIKQ$A%A^qe_{AJ+^U)^1rsHF=)W>ub`AovqXu-y|DvD*!-%n|9c+y7nL z=WM&?#}iH}79&#Ot1r=}iJu4Ph{|g_Jl>`~FgK*YHct&O<`QBVS7md1d@=qk7O`WO z80I?nbn3RXIw4-?4mZO$pq$IFQ#m`YT%&{>yN;#Z#ueVZJ@|zFH4}(f=4K7uQUe3o zEeBMZo6}%UD5{i?EQ%J=sT{s%@T7gMzZ>kHHtd!7Y#z&OI6WBN{TtAfsO4YdHO7!O z+znL$NTjE-t1?q8HbjWd|C!W<(eLjU03B@b$2;SSdeU&eYuN3L=<)QqDv(L^vg=c` zv%4KU5lQ??<5zgZ6P~T25iz$az4KyTbuZ+6Cd2N@vkKbDAUsWv?y2~{!3yal%%m4b zAGyw5E7j`Ep_#1?)!diajA}GmVWD5#r?<>9Um0jksWjpM&w&Cjrb3~635&}2O^g%D zThi;_36y_CRzP2>mTYQEMJRq}B?fK#)}iWGS6XHL1O_-K}*~uPehyVWAMf2r}JNFA;F4asdyE%o?~u+rdA}aKb@0qzIOIZ zKiY%JHf;Neudp`==csz4d+JsF3N&=QMrE1dK5gGmq?UUnls4X*$E>@zlzngz#LM6EA10Lm_w=WvwWp-eTdohojK(vW0*ns+o}Zu7~!Op_q#PF zi~V+cEI=U&`Qz&Y#l6=DJiyKFAT0KKLwItz-&+ z)lDJxMFL7S81z*0Y|$K}{`u13X?dJ_maoNUiNcC$7nI-TyeU(%N3P#1%7WdJ;Zm7<)}}Q>kJ`3rw?JU; zMCXVU=%!Jt?0$C{jh*^gz)OTy;;yLs=#$k1P$^*_rgq4YQj=Ix3Gj|lq_l}zoRwz# zL2_uCfFQx~Uu` z_RXiV$z_2T1VN6Rti_C;HGrUeZm*0yosV#T%O_>!Jy5Eh;LlaV@;CVdmZ zw`Wfjinh$S0GWW2Q@4%@z;a71kf80ZFqFdAySqH27oN?*T7)x{Miim0t=U+i%G05X z7QaW8W6xV{7Izx>sF2#iw9?`mF?zgMaB9<+#JU`p3m{Twz(1b&!^AWan;Unf$$K?aVq@TDNqW~-?1~;EP&>?60 z%xVGo#6BPtg6B3aP2j7~>yTo0XKEA3zl5IaZ{_`&&!hZOkEbRX(|az0Gc@_Z#!;`# zkz)i~(dn^4IXmd+8&%-pEH{FM{l75Fh$4jga`)0)#U*dEg9ass*uXsBX11V2>4@Vg zuKWxIgsFH8P848_5eE&8imNX0k)!RDFAJ%orONB&r96+W3s}-2Y}DFzG0p60GG={P zjD8&>SYJ&)Ytdv>x{Y)xzU35DWx*q2CFa6K$}W9uzuh~t_<;7IO23V*8L5MaxchS2 zQUT`evs{^b(Bt_xD6)TpmOf-{)&h(Z{aPWL%j??Z2Frj#1rC?!WD2s*W611fbv%cA zT?{Nr3(L|;W7w5;_ivcKbILxNyHCHm4w~?5fopLR-EuspMzdHx>^_z5B{!@q4?x=z zuIAX-5yyI5cxOXlcZMSsYUMZQ^k|W$)W#7qbr-P{ky?&3Srqx^KP1Fy7Mt98UKVQM z60rA@%y83CNF3E}Bhb4+NV|mL?=>5F%g~$%dZdc9-)PE#?F!pqA5?!k;%}PqgUq+m zTl~)*8GR1cWb){QR~9MQJ`dL=xPpBgRc5vec^+3-u|+#%Pc(T*R}!+2f`o46xC3VMIWYlY4dmZO(aiul z%_}#x!gbQ1bPVO4G+@{%*2}IW~Vi0>xH|nJ9 zFwIXK%wM^?f9b`Zu+Q$3i#C^<$FLw8B2_Hyjg3Fs3GDrBW^ePnO&mB~Q@hS}8A=(B zFuPxf!e)miU;hd5F&>q$R@eMxkP+dKh53=T(5zMrMMa17#~OXPO`P%55%CR@3QkXv zc=^Q-nSM?n$3V;gQYll_6 z8Et8HYPDl`GRWU$mZtV^5y5jfGJt0iZFK9i-{R$K5-Zg$8;qp%9MqPL*kH{nXb<9* z7c5-TpzcGZ8UdzE|MZ^oU`*@@+_D;b|^bS>=yFzldQp(Ar9 z;>&z-pu4CK!S|{nlX7~87-^FJKOv``V#XPl(7YWg0xNHSkRt`4vwZY6zziSxG7InU zO|mcGS3s!7Vqjro<)ri3A^BsirfP_+>un3TO~G$b&v6_I7-Gq{PldI(Ys4(GZvxYe zeIc{}ut&2|{Iy6vAHHzZm!8Zx!zD~WjJ@uSqtf`p)Hr+uPwr>6N9y7qZIXRXe$Vb0dE4=>)?{IALR!EkL!%pL__7=NesNXqZjTpmV4;jk+PX z$h)NA-x%AVXgYN=ddi7c11`!hoR7Tw=wsrwzi?`2wOGR-6hY~x27b20Fgd?#O+d&z zKU@eNST1(npK^K}4(M$^qZK1xkES9tJ9{WFkR7IJO0_X@~{UBF~bGpm!pjp zk)2+_XYN#k)2cxZn0(l`WUjbcx)@P5%S?XlO=PAgMzIG0?v=sUG##26>$!MA^=D|` z05JTVIM@m*5TkIJ{1DV^!S6@J5puf%mAg)B4xEGmT7&^2@^3r8CDWGez zvwn%iyL6ng;2?sdq?LK%XFc0NSUuY+ja1JdUVpcVm;4*z{1a{S0HSSSY~V~qUC7UX zH>NCM*+Aq2`FBCPS;cB@Iq*WbcSRKz2;Vg1JuZ$@7w?0eTh7Va7h-E?B&*<*O&9Ko9}_<73E%SqAF>A9{e5oNec$#6&&_rAY(; zQJsJEO$5D_%ca4Cs|F>LknTmm)XAX_U_G0Cw*W-xe{$cN(&r~E(c>9QMuTmvM`!G? zLpgpM;FR*DFdErTgs*$3^?Viz%>FTUZ^H0ZXK8*}1(^J!9Be1FkIb$c}Lj0cS> zS5EG|P*AaVUlm3ZI%A<}Omo-Ec0F*^Y;FzHuBKqF!e6Oka~SRkss+dNT}vfo?F2t) z+st{4N$#4Q#V!vCL54IY+AakuhxkuN1?`yZrx`#4F1pp9J}@IM)Tv~z7hQ0-8ba-q ztcu04r!L@MJeK4`8>*(lbpb{?s*1M0yVG;oU?vTL2O-eLR`hn&O1$*OVx8|MY_}Nt zZV5_?N!G$o?YJhx6hz<4^-6UN=2S@U?(dOlS~Zc0f6tQv?oS~u-6Y>7jmF3Zc{?wn z>F4?#?v}gy%JI>?a^&+cmEw)P!GdkBjt>f1`NX;%!OE|+Ih(QdSxZmZEQYn3?_>IV z4-Ce#1&pRjW&;wcL%;{^m(6>$CsSCr>I$p9%kPQk2Pe`w?S_@TAw4B!x&$(J{Z>B5 zDeg*Ho8Tg4<^`@B!v>2Q!0Ayg-i5v$xTbYDAhBW-V6rQK&wgw!KhWD*l!gmb@mfo)^4 z1=MAuIi*%hi8hBd*kYg5L~3&0GTTopnt)07{D!8Pnyhm3>1}&8xC%Ye7o@F{V}fYt zMh&d#uI0`yq$AkHcH`po8`=_iYKB*(?2R9h2qzBCUX zIE=^}hV|YN^y*GheO)Vr`^86+{Tk+x%w(g10du93&-i{9oJ~lgMnC`FI#9Q8kBO$= zY7)pFGLK@?*U9QZ&sgOvY)x*h)sKX6&}j-xIciws972$UcoJ+>KArEc+T{Dxn_fz3 zI5fY|WIe&=4zu4e36OYk@I4c!5+E8Lvbd?&vg2EjlX7Gr98 z1SoNc;CaQX-qqSalhj}eoBV5LvTYgXrLb95=PUT7g>kB%b&2DL!B3`dA`5}_RS zk1=l0D=`w={^hK-gvWw4r_OS4-ND!e4Ig4vKG%ZHn*No=?_%HQHzlpZmO~~klYDDX zb)osl1h2K3mor+rC3L*MYszBKN9}vIhIkuK>RPqwDyRakMfA|0^jL_;IsF!VnxNf- zS7Q2MLt(DeZfBg)_9!eyh1b{D>oLK%@sV^)kqK?j2(-T_YU{?Lzoym{v#tfdP)3m3 z^pp7$&3!{sp}8euk+NXy^y`g7qQ$^@=Txo+)amO$l+07RuBMGdhyIpLk6UlW8?6bF zUH`~y_*hDQHNKCHQkf=mBtReJ4G>0@B9ZkVtSnhWSP0_`KN?UgrT6GWOEj zDGpS$cHY$!k*Q3~>7rV71Pax&5E*0Nck)Z8s$CV1KMp{sM?`aQ+%Ttzb%hSlQ6byN z_x1#7r$wh$42rE8T%yrBuxv%Yf+#?2zC2x+jq}2j`s^V;_^XnKtkNiDR z4@)-Ht)5Jo^Ni|}@>RD27Ri7nJs?J~fH<{yy#4x<)*4*Evr>6Ae8 z*43Gbp3c4wKW&%42vL!Zehe$XRiKp5IIYDvdW9W~fbVVPz=j1lHh*2Q3v@QU&7i?x zIKXx(4*{c{J%&3r$kymhvffwCdIghGGnoku0|L$G)K4U<7^lsMb{({?uQAeLY>Aap zIL!`^jq1!Xj}}S&&Ot7aAB}Oc@Wva#Cjvdb(I_gb(iqh?Wm+x+eH5xAluiY0w~f4S z!#gQeQ`K8m<%(QVou8Cr-n#FpL70k}A$eNQbqGZ&&-^_z;t*%7fo-C=RbJ$QxzL(Wq9-%z= zyBelPhO(I^TbYi+N8M_=F2bA5+x9z@hlRJK&2I~yh~78c=g5SeBN#Z;<@J)8DOLC< ztSAv?yjgaJzVmUMW{mlPH|Kk}21!pu|1yhT1n~2za7%7#n*bFW#gVGs1CYz&n2dla z9X}fV*JF&MQsm0BPi<0yoV6)HTI@FnK@Cc7vs_^Y<}?a(xx?dW(Q#1tAxNQ#l?Is|m)&}3<=0ZjW z3zi5coYs=e2qf7%H15t9YIcjxim&%xif8OFZHj;&j0>tt=uX0HGuw><^;-_1U~E~y z9`->Pb={<$MUPQ{s}oruyfNU6Nm69$h5EMar`3S-pmt%LBXKk+h2O@osLf1U(1DA0 z@HJE*yZPIQNldl00TM%>gO|o@zvMWj;z)tC-HovJod^Eg%M)^`)@bRX2{K^J3~tH4 zcu!gkD8@-m`@Pi0Y6M`j(qKnaBsgaG)bF)|eXN4C;W$9QF8M}*UH zv8j?o<-LS++puotE+S48c)Wald;tcw!p0DgxF!=hw$t9ndg6`&`y!c4O>DtuHtf(J z!q7Hw5mO7|NfcMk=!>9iGx&5;D@o|!dF%SL!u-Qoqw<@+)*AWHbnS-r$0keyW7^CL z;UJN|8>i2ze0Hs?au97AccopauXMJLCy)XRM!JsV70vZva0G0%zSyF&3;`o*9jN z$F-ey>)jI(L@unV2|Qb)?PSrR>Z7HHT0M-+_Jbq}9YNM<913yrhoNu&T0kFp+v}mdTf5J~1J|Mx zFrmpUUKaPSxI};l@?4jypl7eQqD4VAmT-nq%B4sllSk@dWh8@C9G=JPw!CE^+Br9K zte7htYaBJ=1LuboE*R8(X%yL~x4~75S&C+tS9E&(>5#lyivFA0SsnO&q-Ww4QzK$7 zAID!8*5$zi2ZIAaGDkgxmKP8Amzs>(S9tfVw|V^VPDR;-7$6zM3V+DsCz$UVR$hAI zA;%+9=5G2UEU~w;qunbKE-R0=^HU2-e8FaOJJoA;*n(!aU7k-U|KEnNe^IP}Sm*%N zB83nweF5B&LKM+`2zu6`Bl}xnGy?%c^~x!_SbQuV{QkG8WTe9t zM))6_2gK^lH=FrahXu`T`n8+Do|sEzF6Jd?jb|}y$-jM_TVnsPtpGxm1<}@hudLDd z&YwD7AK7M*Y#4%orJ*Bh+!y1Ls)71f`gs0>6eT`Qc0)j8yg;9b5gcZY0Z8wyW@6s` zxV;uV+6$Y_ioI!q(d@9Ty~TeP3UGc%+3A^eIi5S1g_-(&H<6`zJpOvn4O3^lF)j2x zmI#sQtcheOnUT`_KgHAkCWa!=VA)ojwpYCReW+@+jdd1NJPdr;#v)6tBTJ8gKZaBi z|AEi{0=;ZW>^FPh8YVpwq!gmApxFohFTR+A0$Y@!&ILyH(dIHkjaK;|HnhJrgLMWA zNnP>+^jHpAI`W@El>dKkTUQlZ&*!Ee)rDrLyYh()l6$24Z-Da*>t7&LhdxdAGzT5r z0@zK>*#Bt>vz*QXY>Bsg zwaMJoG1pqn$?>K`SjEAA+Q2@SBK~h1SdUC%1^`7dfHp94yPEQcFCOugN~s3atX%M5 zr&@EOPWbLiw&l4K&uCo3FfOn_tCKbL9_mh8Lgk6tRz@+rw zUd%wDeqxke`lkE4Z(Bjd3Do%OWlXYAx+*dKs%EoLQ+;sJJUlqeLbENh?{PG__Y5nwieR+Te%sp;- zPpaQRHEr}Pa@g+9$xg(n=#%`=n*D)j8sY1?c)HtdBevJeu=0xQd#f#pnB{=fu z5ZfAhS~ONvscsC}^A)q;q}?PoQWW>PkB%2hz7WtF5+0gJ1QbWi)LKnBlh{-vXw>S& zv4AjD9Cw-CU%}b=02vCpZJ+vQtDi}Vgom+2{(4Dx|6-GJZGo=5Ek@3M@Mm}vwt7-f zp{|)1s^)os^zAX7Ik*C?no@0e5Ia^j1q?C<5CrD+^8s1xp#8UbJVc|9QeEl&iSHwC zm_yR5$gK`ws4a&C1KVp{>Z1}~q)TiEc>v)Gwi6w`%%7etDu7OS48TeB zk7Hl5eXB$Pqed2oVgrSd46E|{iZ~C5#fb-qC2GJqj!vyZ7rVGk zchT9AJU(Nb6)WHJg1FUoOR^X+wx>GFV`W?1$M0pI{oS=vl5;F{`9tlgb14;??89Mw z0gz$PV&j+B5`C(*-(uX~o^`3SITf?yvWB-JjV^RRiYm>sx*?JsJ6$Uj^kOfB4x&`P z7;FBM!P set foo bar\nOK\nredis> get foo\n"bar"\n')])])]),s("h3",{attrs:{id:"安装apollo配置中心"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#安装apollo配置中心"}},[a._v("#")]),a._v(" 安装Apollo配置中心")]),a._v(" "),s("p",[a._v("说明: apollo是可选组件,如果不使用apollo可使用本地配置文件(application.yml), 如果不使用apollo可跳过此步骤。")]),a._v(" "),s("p",[a._v("安装步骤详见apollo官方文档: "),s("a",{attrs:{href:"https://github.com/ctripcorp/apollo/wiki/Quick-Start",target:"_blank",rel:"noopener noreferrer"}},[s("OutboundLink")],1)]),a._v(" "),s("h3",{attrs:{id:"安装eureka服务注册中心"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#安装eureka服务注册中心"}},[a._v("#")]),a._v(" 安装Eureka服务注册中心")]),a._v(" "),s("p",[a._v("环境要求:")]),a._v(" "),s("ul",[s("li",[a._v("JDK 1.8 或以上版本")]),a._v(" "),s("li",[a._v("Tomcat 6.0.10 或以上版本 (如使用spring cloud已内置)")])]),a._v(" "),s("ol",[s("li",[a._v("安装JDK 1.8")])]),a._v(" "),s("p",[a._v("1)下载JDK,如: jdk-8u192-linux-x64.tar.gz")]),a._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[a._v("tar -zxvf jdk-8u192-linux-x64.tar.gz\nmv jdk1.8.0_192 /usr/local/\n\n")])])]),s("p",[a._v("2)设置JDK环境变量,将下面内容追回到/etc/profile文件后面")]),a._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[a._v("JAVA_HOME=/usr/local/jdk/jdk1.8.0_192\nJRE_HOME=$JAVA_HOME/jre\nPATH=$PATH:$JAVA_HOME/bin:$JRE_HOME/bin\nCLASSPATH=:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JRE_HOME/lib/dt.jar\nexport JAVA_HOME JRE_HOME PATH CLASSPATH\n\n")])])]),s("p",[a._v("3)执行以下命令全环境变量生效:")]),a._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[a._v("source /etc/profile\n\n")])])]),s("p",[a._v("4)查看是否安装成功")]),a._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[a._v("java -version\n")])])]),s("ol",{attrs:{start:"2"}},[s("li",[a._v("安装eureka")])]),a._v(" "),s("p",[a._v("1)使用IDE创建一个spring boot项目,如:sc-eureka-server")]),a._v(" "),s("p",[a._v("pom.xml:")]),a._v(" "),s("div",{staticClass:"language-xml extra-class"},[s("pre",{pre:!0,attrs:{class:"language-xml"}},[s("code",[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("<")]),a._v("dependency")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(">")])]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("<")]),a._v("groupId")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(">")])]),a._v("org.springframework.cloud"),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("")])]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("<")]),a._v("artifactId")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(">")])]),a._v("spring-cloud-starter-netflix-eureka-server"),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("")])]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("")])]),a._v("\n")])])]),s("p",[a._v("在启动类上添加@EnableEurekaServer注解来启用Euerka注册中心功能:")]),a._v(" "),s("div",{staticClass:"language-java extra-class"},[s("pre",{pre:!0,attrs:{class:"language-java"}},[s("code",[s("span",{pre:!0,attrs:{class:"token annotation punctuation"}},[a._v("@SpringBootApplication")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token annotation punctuation"}},[a._v("@EnableEurekaServer")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("public")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("class")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[a._v("ScEurekaServerApplication")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n\n\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("public")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("static")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("void")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("main")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[a._v("String")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("]")]),a._v(" args"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token class-name"}},[a._v("SpringApplication")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("run")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[a._v("ScEurekaServerApplication")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(".")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("class")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v(" args"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),a._v("\n\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),a._v("\n")])])]),s("p",[a._v("application.properties配置文件:")]),a._v(" "),s("div",{staticClass:"language-properties extra-class"},[s("pre",{pre:!0,attrs:{class:"language-properties"}},[s("code",[s("span",{pre:!0,attrs:{class:"token attr-name"}},[a._v("spring.application.name")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),s("span",{pre:!0,attrs:{class:"token attr-value"}},[a._v("sc-eureka-server")]),a._v("\n\n"),s("span",{pre:!0,attrs:{class:"token attr-name"}},[a._v("server.port")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),s("span",{pre:!0,attrs:{class:"token attr-value"}},[a._v("8761")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token attr-name"}},[a._v("eureka.instance.hostname")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),s("span",{pre:!0,attrs:{class:"token attr-value"}},[a._v("localhost")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token attr-name"}},[a._v("eureka.client.registerWithEureka")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),s("span",{pre:!0,attrs:{class:"token attr-value"}},[a._v("false")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token attr-name"}},[a._v("eureka.client.fetchRegistry")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),s("span",{pre:!0,attrs:{class:"token attr-value"}},[a._v("false")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token attr-name"}},[a._v("eureka.server.enableSelfPreservation")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),s("span",{pre:!0,attrs:{class:"token attr-value"}},[a._v("false")]),a._v("\n")])])]),s("p",[a._v("2) maven构建并运行sc-eureka-server应用, 启动后访问地址http://localhost:8761/可以看到Eureka注册中心的界面")]),a._v(" "),s("p",[a._v("3)把target/sc-eureka-server-1.0.0.jar传到linux服务器上运行. (仅以单机部署为例)")]),a._v(" "),s("div",{staticClass:"language-shell extra-class"},[s("pre",{pre:!0,attrs:{class:"language-shell"}},[s("code",[a._v("nohub java -jar sc-eureka-server-1.0.0.jar "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("&")]),a._v(" \n")])])]),s("p",[a._v("4)eureka客户端的注册地址为:http://localhost:8761/eureka/ (替换localhost为服务器的IP)")]),a._v(" "),s("div",{staticClass:"language-properties extra-class"},[s("pre",{pre:!0,attrs:{class:"language-properties"}},[s("code",[s("span",{pre:!0,attrs:{class:"token attr-name"}},[a._v("eureka.client.serviceUrl.defaultZone")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token attr-value"}},[a._v("http://localhost:8761/eureka/")]),a._v("\n")])])]),s("h2",{attrs:{id:"安装fizz"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#安装fizz"}},[a._v("#")]),a._v(" 安装Fizz")]),a._v(" "),s("h3",{attrs:{id:"管理后台"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#管理后台"}},[a._v("#")]),a._v(" 管理后台")]),a._v(" "),s("p",[a._v("从github的releases(https://github.com/wehotel/fizz-gateway-community/releases)下载 fizz-manager-professional 和 fizz-admin-professional 的安装包")]),a._v(" "),s("ul",[s("li",[a._v("管理后台服务端(fizz-manager-professional)")])]),a._v(" "),s("ol",[s("li",[a._v("首次安装执行"),s("code",[a._v("fizz-manager-professional-1.1.0-mysql.sql")]),a._v("数据库脚本,低版本升级执行"),s("code",[a._v("update")]),a._v("目录下的升级脚本")]),a._v(" "),s("li",[a._v("将"),s("code",[a._v("application-prod.yml")]),a._v("、"),s("code",[a._v("boot.sh")]),a._v("、"),s("code",[a._v("fizz-manager-professional-1.1.0.jar")]),a._v("拷贝到"),s("code",[a._v("/data/webapps/fizz-manager-professional")]),a._v("目录下")]),a._v(" "),s("li",[a._v("修改"),s("code",[a._v("application-prod.yml")]),a._v("文件,将相关配置修改成部署环境的配置")]),a._v(" "),s("li",[a._v("修改"),s("code",[a._v("boot.sh")]),a._v("文件,将"),s("code",[a._v("RUN_CMD")]),a._v("变量值修改成部署环境的JAVA实际路径")]),a._v(" "),s("li",[a._v("执行 "),s("code",[a._v("chmod +x boot.sh")]),a._v(" 命令给"),s("code",[a._v("boot.sh")]),a._v("增加执行权限")]),a._v(" "),s("li",[a._v("执行 "),s("code",[a._v("./boot.sh start")]),a._v(" 命令启动服务,支持 start/stop/restart(升级发布时需要手动kill原进程)/status命令")]),a._v(" "),s("li",[a._v("服务启动后访问前端登录地址,使用超级管理员账户"),s("code",[a._v("admin")]),a._v("密码"),s("code",[a._v("Aa123!")]),a._v("登录")])]),a._v(" "),s("ul",[s("li",[a._v("管理后台前端(fizz-admin-professional)")])]),a._v(" "),s("p",[a._v("zip资源包解压后,取文件夹【fizzAdmin】放置于服务器静态数据存放目录 如:/home/data/")]),a._v(" "),s("p",[a._v("nginx配置")]),a._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[a._v("server {\n listen 9000;\n server_name localhost:9000;\n location / {\n root /home/data/fizzAdmin;\n }\n location ^~ /api {\n rewrite ^/api/(.*) /$1 break;\n proxy_pass http://127.0.0.1:8000;\n }\n}\n\n# 注:root中地址需与资源包存放目录路径一致\n# 注:http://127.0.0.1:8000 为管理后台(fizz-manager-professional)的访问地址\n")])])]),s("p",[a._v("访问地址")]),a._v(" "),s("p",[a._v("【资源部署服务器IP + 端口号】如:http://127.0.0.1:9000/")]),a._v(" "),s("p",[a._v("(端口号与nginx配置端口号一致)")]),a._v(" "),s("h3",{attrs:{id:"fizz-gateway-community社区版"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#fizz-gateway-community社区版"}},[a._v("#")]),a._v(" fizz-gateway-community社区版")]),a._v(" "),s("p",[a._v("说明:如果使用apollo配置中心,可把application.yml文件内容迁到配置中心(apollo上应用名为:fizz-gateway);使用不使用apollo可去掉下面启动命令里的apollo参数。")]),a._v(" "),s("p",[a._v("脚本启动:")]),a._v(" "),s("ol",[s("li",[a._v("下载fizz-gateway-community的最新代码,修改application.yml配置文件里eureka、redis的配置,使用maven构建好并把构建好的fizz-gateway-community-1.0.0.jar和boot.sh放同一目录")]),a._v(" "),s("li",[a._v("修改boot.sh脚本的apollo连接,JVM内存配置,")]),a._v(" "),s("li",[a._v("执行 "),s("code",[a._v("./boot.sh start")]),a._v(" 命令启动服务,支持 start/stop/restart/status命令")])]),a._v(" "),s("p",[a._v("IDE启动:")]),a._v(" "),s("ol",[s("li",[a._v("本地clone仓库上的最新代码")]),a._v(" "),s("li",[a._v("将项目fizz-gateway导入IDE")]),a._v(" "),s("li",[a._v("导入完成后设置项目启动配置及修改application.yml配置文件里eureka、redis的配置,在VM选项中加入"),s("code",[a._v("-Denv=dev -Dapollo.meta=http://localhost:66")]),a._v("(Apollo配置中心地址)")])]),a._v(" "),s("p",[a._v("jar启动:")]),a._v(" "),s("ol",[s("li",[a._v("本地clone仓库上的最新代码,修改application.yml配置文件里eureka、redis的配置")]),a._v(" "),s("li",[a._v("在项目根目录fizz-gateway-community下执行Maven命令"),s("code",[a._v("mvn clean package -DskipTests=true")]),a._v("打包")]),a._v(" "),s("li",[a._v("进入target目录,使用命令"),s("code",[a._v("java -jar -Denv=DEV -Dapollo.meta=http://localhost:66 fizz-gateway-community-1.0.0.jar")]),a._v("启动服务")])]),a._v(" "),s("p",[a._v("网关访问地址格式:")]),a._v(" "),s("p",[a._v("http://127.0.0.1:8600/proxy/[服务名]/[API Path]")])])}),[],!1,null,null,null);t.default=r.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[12],{361:function(a,t,s){"use strict";s.r(t);var e=s(42),r=Object(e.a)({},(function(){var a=this,t=a.$createElement,s=a._self._c||t;return s("ContentSlotsDistributor",{attrs:{"slot-key":a.$parent.slotKey}},[s("h2",{attrs:{id:"安装依赖"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#安装依赖"}},[a._v("#")]),a._v(" 安装依赖")]),a._v(" "),s("p",[a._v("安装以下依赖软件:")]),a._v(" "),s("ul",[s("li",[a._v("Redis 2.8或以上版本")]),a._v(" "),s("li",[a._v("MySQL 5.7或以上版本")]),a._v(" "),s("li",[a._v("Apollo配置中心 (可选)")]),a._v(" "),s("li",[a._v("Eureka服务注册中心")])]),a._v(" "),s("h3",{attrs:{id:"安装mysql"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#安装mysql"}},[a._v("#")]),a._v(" 安装MySQL")]),a._v(" "),s("ul",[s("li",[a._v("操作系统 CentOS 6.5")]),a._v(" "),s("li",[a._v("MySQL 5.7.30")])]),a._v(" "),s("ol",[s("li",[a._v("下载MySQL")])]),a._v(" "),s("div",{staticClass:"language-shell extra-class"},[s("pre",{pre:!0,attrs:{class:"language-shell"}},[s("code",[s("span",{pre:!0,attrs:{class:"token function"}},[a._v("wget")]),a._v(" https://downloads.mysql.com/archives/get/p/23/file/mysql-5.7.30-1.el6.x86_64.rpm-bundle.tar\n")])])]),s("ol",{attrs:{start:"2"}},[s("li",[a._v("解压")])]),a._v(" "),s("div",{staticClass:"language-shell extra-class"},[s("pre",{pre:!0,attrs:{class:"language-shell"}},[s("code",[s("span",{pre:!0,attrs:{class:"token function"}},[a._v("tar")]),a._v(" -xvf mysql-5.7.30-1.el6.x86_64.rpm-bundle.tar\n")])])]),s("ol",{attrs:{start:"3"}},[s("li",[a._v("安装")])]),a._v(" "),s("div",{staticClass:"language-shell extra-class"},[s("pre",{pre:!0,attrs:{class:"language-shell"}},[s("code",[s("span",{pre:!0,attrs:{class:"token function"}},[a._v("sudo")]),a._v(" yum "),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("install")]),a._v(" mysql-community-"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("server,client,common,libs"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),a._v("-*\n")])])]),s("ol",{attrs:{start:"4"}},[s("li",[a._v("启动")])]),a._v(" "),s("div",{staticClass:"language-shell extra-class"},[s("pre",{pre:!0,attrs:{class:"language-shell"}},[s("code",[s("span",{pre:!0,attrs:{class:"token function"}},[a._v("sudo")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("service")]),a._v(" mysqld start\n")])])]),s("p",[a._v("启动成功会显示以下信息:")]),a._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[a._v("[root@localhost ~]# sudo service mysqld start\nInitializing MySQL database: [ OK ]\nStarting mysqld: [ OK ]\n")])])]),s("ol",{attrs:{start:"5"}},[s("li",[a._v("初始密码")])]),a._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[a._v("sudo grep 'temporary password' /var/log/mysqld.log\n")])])]),s("ol",{attrs:{start:"6"}},[s("li",[a._v("使用初始密码登录")])]),a._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[a._v("mysql -uroot -p\n")])])]),s("ol",{attrs:{start:"7"}},[s("li",[a._v("修改密码")])]),a._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[a._v("ALTER USER 'root'@'localhost' IDENTIFIED BY 'MyNewPass4!';\n")])])]),s("ol",{attrs:{start:"8"}},[s("li",[a._v("退出登录")])]),a._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[a._v("quit\n")])])]),s("h3",{attrs:{id:"安装redis-6-0-8"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#安装redis-6-0-8"}},[a._v("#")]),a._v(" 安装Redis 6.0.8")]),a._v(" "),s("ol",[s("li",[a._v("下载解压并编译")])]),a._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[a._v("$ wget http://download.redis.io/releases/redis-6.0.8.tar.gz\n$ tar xzf redis-6.0.8.tar.gz\n$ cd redis-6.0.8\n$ make\n")])])]),s("ol",{attrs:{start:"2"}},[s("li",[a._v("启动redis")])]),a._v(" "),s("p",[a._v("运行编译后的文件:")]),a._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[a._v("$ src/redis-server\n")])])]),s("ol",{attrs:{start:"3"}},[s("li",[a._v("客户端连接")])]),a._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[a._v('$ src/redis-cli\nredis> set foo bar\nOK\nredis> get foo\n"bar"\n')])])]),s("h3",{attrs:{id:"安装apollo配置中心"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#安装apollo配置中心"}},[a._v("#")]),a._v(" 安装Apollo配置中心")]),a._v(" "),s("p",[a._v("说明: apollo是可选组件,如果不使用apollo可使用本地配置文件(application.yml), 如果不使用apollo可跳过此步骤。")]),a._v(" "),s("p",[a._v("安装步骤详见apollo官方文档: "),s("a",{attrs:{href:"https://github.com/ctripcorp/apollo/wiki/Quick-Start",target:"_blank",rel:"noopener noreferrer"}},[s("OutboundLink")],1)]),a._v(" "),s("h3",{attrs:{id:"安装eureka服务注册中心"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#安装eureka服务注册中心"}},[a._v("#")]),a._v(" 安装Eureka服务注册中心")]),a._v(" "),s("p",[a._v("环境要求:")]),a._v(" "),s("ul",[s("li",[a._v("JDK 1.8 或以上版本")]),a._v(" "),s("li",[a._v("Tomcat 6.0.10 或以上版本 (如使用spring cloud已内置)")])]),a._v(" "),s("ol",[s("li",[a._v("安装JDK 1.8")])]),a._v(" "),s("p",[a._v("1)下载JDK,如: jdk-8u192-linux-x64.tar.gz")]),a._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[a._v("tar -zxvf jdk-8u192-linux-x64.tar.gz\nmv jdk1.8.0_192 /usr/local/\n\n")])])]),s("p",[a._v("2)设置JDK环境变量,将下面内容追回到/etc/profile文件后面")]),a._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[a._v("JAVA_HOME=/usr/local/jdk/jdk1.8.0_192\nJRE_HOME=$JAVA_HOME/jre\nPATH=$PATH:$JAVA_HOME/bin:$JRE_HOME/bin\nCLASSPATH=:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JRE_HOME/lib/dt.jar\nexport JAVA_HOME JRE_HOME PATH CLASSPATH\n\n")])])]),s("p",[a._v("3)执行以下命令全环境变量生效:")]),a._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[a._v("source /etc/profile\n\n")])])]),s("p",[a._v("4)查看是否安装成功")]),a._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[a._v("java -version\n")])])]),s("ol",{attrs:{start:"2"}},[s("li",[a._v("安装eureka")])]),a._v(" "),s("p",[a._v("1)使用IDE创建一个spring boot项目,如:sc-eureka-server")]),a._v(" "),s("p",[a._v("pom.xml:")]),a._v(" "),s("div",{staticClass:"language-xml extra-class"},[s("pre",{pre:!0,attrs:{class:"language-xml"}},[s("code",[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("<")]),a._v("dependency")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(">")])]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("<")]),a._v("groupId")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(">")])]),a._v("org.springframework.cloud"),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("")])]),a._v("\n "),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("<")]),a._v("artifactId")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(">")])]),a._v("spring-cloud-starter-netflix-eureka-server"),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("")])]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token tag"}},[s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("")])]),a._v("\n")])])]),s("p",[a._v("在启动类上添加@EnableEurekaServer注解来启用Euerka注册中心功能:")]),a._v(" "),s("div",{staticClass:"language-java extra-class"},[s("pre",{pre:!0,attrs:{class:"language-java"}},[s("code",[s("span",{pre:!0,attrs:{class:"token annotation punctuation"}},[a._v("@SpringBootApplication")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token annotation punctuation"}},[a._v("@EnableEurekaServer")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("public")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("class")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token class-name"}},[a._v("ScEurekaServerApplication")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n\n\t"),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("public")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("static")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("void")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("main")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[a._v("String")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("]")]),a._v(" args"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("{")]),a._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token class-name"}},[a._v("SpringApplication")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[a._v("run")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("(")]),s("span",{pre:!0,attrs:{class:"token class-name"}},[a._v("ScEurekaServerApplication")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(".")]),s("span",{pre:!0,attrs:{class:"token keyword"}},[a._v("class")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(",")]),a._v(" args"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v(";")]),a._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),a._v("\n\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("}")]),a._v("\n")])])]),s("p",[a._v("application.properties配置文件:")]),a._v(" "),s("div",{staticClass:"language-properties extra-class"},[s("pre",{pre:!0,attrs:{class:"language-properties"}},[s("code",[s("span",{pre:!0,attrs:{class:"token attr-name"}},[a._v("spring.application.name")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),s("span",{pre:!0,attrs:{class:"token attr-value"}},[a._v("sc-eureka-server")]),a._v("\n\n"),s("span",{pre:!0,attrs:{class:"token attr-name"}},[a._v("server.port")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),s("span",{pre:!0,attrs:{class:"token attr-value"}},[a._v("8761")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token attr-name"}},[a._v("eureka.instance.hostname")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),s("span",{pre:!0,attrs:{class:"token attr-value"}},[a._v("localhost")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token attr-name"}},[a._v("eureka.client.registerWithEureka")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),s("span",{pre:!0,attrs:{class:"token attr-value"}},[a._v("false")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token attr-name"}},[a._v("eureka.client.fetchRegistry")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),s("span",{pre:!0,attrs:{class:"token attr-value"}},[a._v("false")]),a._v("\n"),s("span",{pre:!0,attrs:{class:"token attr-name"}},[a._v("eureka.server.enableSelfPreservation")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),s("span",{pre:!0,attrs:{class:"token attr-value"}},[a._v("false")]),a._v("\n")])])]),s("p",[a._v("2) maven构建并运行sc-eureka-server应用, 启动后访问地址http://localhost:8761/可以看到Eureka注册中心的界面")]),a._v(" "),s("p",[a._v("3)把target/sc-eureka-server-1.0.0.jar传到linux服务器上运行. (仅以单机部署为例)")]),a._v(" "),s("div",{staticClass:"language-shell extra-class"},[s("pre",{pre:!0,attrs:{class:"language-shell"}},[s("code",[a._v("nohub java -jar sc-eureka-server-1.0.0.jar "),s("span",{pre:!0,attrs:{class:"token operator"}},[a._v("&")]),a._v(" \n")])])]),s("p",[a._v("4)eureka客户端的注册地址为:http://localhost:8761/eureka/ (替换localhost为服务器的IP)")]),a._v(" "),s("div",{staticClass:"language-properties extra-class"},[s("pre",{pre:!0,attrs:{class:"language-properties"}},[s("code",[s("span",{pre:!0,attrs:{class:"token attr-name"}},[a._v("eureka.client.serviceUrl.defaultZone")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[a._v("=")]),a._v(" "),s("span",{pre:!0,attrs:{class:"token attr-value"}},[a._v("http://localhost:8761/eureka/")]),a._v("\n")])])]),s("h2",{attrs:{id:"安装fizz"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#安装fizz"}},[a._v("#")]),a._v(" 安装Fizz")]),a._v(" "),s("h3",{attrs:{id:"管理后台"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#管理后台"}},[a._v("#")]),a._v(" 管理后台")]),a._v(" "),s("p",[a._v("从github的releases(https://github.com/wehotel/fizz-gateway-community/releases)下载 fizz-manager-professional 和 fizz-admin-professional 的安装包")]),a._v(" "),s("ul",[s("li",[a._v("管理后台服务端(fizz-manager-professional)")])]),a._v(" "),s("ol",[s("li",[a._v("首次安装执行"),s("code",[a._v("fizz-manager-professional-1.1.0-mysql.sql")]),a._v("数据库脚本,低版本升级执行"),s("code",[a._v("update")]),a._v("目录下的升级脚本")]),a._v(" "),s("li",[a._v("将"),s("code",[a._v("application-prod.yml")]),a._v("、"),s("code",[a._v("boot.sh")]),a._v("、"),s("code",[a._v("fizz-manager-professional-1.1.0.jar")]),a._v("拷贝到"),s("code",[a._v("/data/webapps/fizz-manager-professional")]),a._v("目录下")]),a._v(" "),s("li",[a._v("修改"),s("code",[a._v("application-prod.yml")]),a._v("文件,将相关配置修改成部署环境的配置")]),a._v(" "),s("li",[a._v("修改"),s("code",[a._v("boot.sh")]),a._v("文件,将"),s("code",[a._v("RUN_CMD")]),a._v("变量值修改成部署环境的JAVA实际路径")]),a._v(" "),s("li",[a._v("执行 "),s("code",[a._v("chmod +x boot.sh")]),a._v(" 命令给"),s("code",[a._v("boot.sh")]),a._v("增加执行权限")]),a._v(" "),s("li",[a._v("执行 "),s("code",[a._v("./boot.sh start")]),a._v(" 命令启动服务,支持 start/stop/restart(升级发布时需要手动kill原进程)/status命令")]),a._v(" "),s("li",[a._v("服务启动后访问前端登录地址,使用超级管理员账户"),s("code",[a._v("admin")]),a._v("密码"),s("code",[a._v("Aa123!")]),a._v("登录")])]),a._v(" "),s("ul",[s("li",[a._v("管理后台前端(fizz-admin-professional)")])]),a._v(" "),s("p",[a._v("zip资源包解压后,取文件夹【fizzAdmin】放置于服务器静态数据存放目录 如:/home/data/")]),a._v(" "),s("p",[a._v("nginx配置")]),a._v(" "),s("div",{staticClass:"language- extra-class"},[s("pre",{pre:!0,attrs:{class:"language-text"}},[s("code",[a._v("server {\n listen 9000;\n server_name localhost:9000;\n location / {\n root /home/data/fizzAdmin;\n }\n location ^~ /api {\n rewrite ^/api/(.*) /$1 break;\n proxy_pass http://127.0.0.1:8000;\n }\n}\n\n# 注:root中地址需与资源包存放目录路径一致\n# 注:http://127.0.0.1:8000 为管理后台(fizz-manager-professional)的访问地址\n")])])]),s("p",[a._v("访问地址")]),a._v(" "),s("p",[a._v("【资源部署服务器IP + 端口号】如:http://127.0.0.1:9000/")]),a._v(" "),s("p",[a._v("(端口号与nginx配置端口号一致)")]),a._v(" "),s("h3",{attrs:{id:"fizz-gateway-community社区版"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#fizz-gateway-community社区版"}},[a._v("#")]),a._v(" fizz-gateway-community社区版")]),a._v(" "),s("p",[a._v("说明:如果使用apollo配置中心,可把application.yml文件内容迁到配置中心(apollo上应用名为:fizz-gateway);使用不使用apollo可去掉下面启动命令里的apollo参数。")]),a._v(" "),s("p",[a._v("脚本启动:")]),a._v(" "),s("ol",[s("li",[a._v("下载fizz-gateway-community的最新代码,修改application.yml配置文件里eureka、redis的配置,使用maven构建好并把构建好的fizz-gateway-community-1.0.0.jar和boot.sh放同一目录")]),a._v(" "),s("li",[a._v("修改boot.sh脚本的apollo连接,JVM内存配置,")]),a._v(" "),s("li",[a._v("执行 "),s("code",[a._v("./boot.sh start")]),a._v(" 命令启动服务,支持 start/stop/restart/status命令")])]),a._v(" "),s("p",[a._v("IDE启动:")]),a._v(" "),s("ol",[s("li",[a._v("本地clone仓库上的最新代码")]),a._v(" "),s("li",[a._v("将项目fizz-gateway导入IDE")]),a._v(" "),s("li",[a._v("导入完成后设置项目启动配置及修改application.yml配置文件里eureka、redis的配置,在VM选项中加入"),s("code",[a._v("-Denv=dev -Dapollo.meta=http://localhost:66")]),a._v("(Apollo配置中心地址)")])]),a._v(" "),s("p",[a._v("jar启动:")]),a._v(" "),s("ol",[s("li",[a._v("本地clone仓库上的最新代码,修改application.yml配置文件里eureka、redis的配置")]),a._v(" "),s("li",[a._v("在项目根目录fizz-gateway-community下执行Maven命令"),s("code",[a._v("mvn clean package -DskipTests=true")]),a._v("打包")]),a._v(" "),s("li",[a._v("进入target目录,使用命令"),s("code",[a._v("java -jar -Denv=DEV -Dapollo.meta=http://localhost:66 fizz-gateway-community-1.0.0.jar")]),a._v("启动服务")])]),a._v(" "),s("p",[a._v("网关访问地址格式:")]),a._v(" "),s("p",[a._v("http://127.0.0.1:8600/proxy/[服务名]/[API Path]")])])}),[],!1,null,null,null);t.default=r.exports}}]); \ No newline at end of file diff --git a/docs/assets/js/13.fdb2bea3.js b/docs/assets/js/13.beb516ad.js similarity index 97% rename from docs/assets/js/13.fdb2bea3.js rename to docs/assets/js/13.beb516ad.js index f765695..79afc60 100644 --- a/docs/assets/js/13.fdb2bea3.js +++ b/docs/assets/js/13.beb516ad.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[13],{361:function(t,a,v){"use strict";v.r(a);var i=v(42),_=Object(i.a)({},(function(){var t=this,a=t.$createElement,v=t._self._c||a;return v("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[v("h2",{attrs:{id:"什么是fizz网关"}},[v("a",{staticClass:"header-anchor",attrs:{href:"#什么是fizz网关"}},[t._v("#")]),t._v(" 什么是Fizz网关")]),t._v(" "),v("p",[t._v("A Managerment API Gateway in Java . Fizz Gateway 是一个基于 Java开发的微服务网关,能够实现热服务编排、自动授权选择、线上服务脚本编码、在线测试、高性能路由、API审核管理等目的,拥有强大的自定义插件系统可以自行扩展,并且提供友好的图形化配置界面,能够快速帮助企业进行API服务治理、减少中间层胶水代码以及降低编码投入、提高 API 服务的稳定性和安全性。")]),t._v(" "),v("h2",{attrs:{id:"fizz的设计"}},[v("a",{staticClass:"header-anchor",attrs:{href:"#fizz的设计"}},[t._v("#")]),t._v(" Fizz的设计")]),t._v(" "),v("p",[v("img",{attrs:{src:"/fizz_design.png",alt:""}})]),t._v(" "),v("h2",{attrs:{id:"产品特性"}},[v("a",{staticClass:"header-anchor",attrs:{href:"#产品特性"}},[t._v("#")]),t._v(" 产品特性")]),t._v(" "),v("ul",[v("li",[t._v("集群管理:Fizz网关节点是无状态的,配置信息自动同步,支持节点水平拓展和多集群部署。")]),t._v(" "),v("li",[t._v("服务编排:支持热服务编排能力,支持前后端编码,随时随地更新API。")]),t._v(" "),v("li",[t._v("负载均衡:支持round-robin负载均衡。")]),t._v(" "),v("li",[t._v("服务发现:支持从Eureka注册中心发现后端服务器。")]),t._v(" "),v("li",[t._v("配置中心:支持接入apollo配置中心。")]),t._v(" "),v("li",[t._v("HTTP反向代理:隐藏真实后端服务,支持 Rest API反向代理。")]),t._v(" "),v("li",[t._v("访问策略:支持不同策略访问不同的API、配置不同的鉴权等。")]),t._v(" "),v("li",[t._v("IP黑白名单:支持配置IP黑白名单。")]),t._v(" "),v("li",[t._v("自定义插件:强大的插件机制支持自由扩展。")]),t._v(" "),v("li",[t._v("可扩展:简单易用的插件机制方便扩展功能。")]),t._v(" "),v("li",[t._v("高性能:性能在众多网关之中表现优异。")]),t._v(" "),v("li",[t._v("版本控制:支持操作的发布和多次回滚。")]),t._v(" "),v("li",[t._v("管理后台:通过管理后台界面对网关集群进行各项配置。")])])])}),[],!1,null,null,null);a.default=_.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[13],{357:function(t,a,v){"use strict";v.r(a);var i=v(42),_=Object(i.a)({},(function(){var t=this,a=t.$createElement,v=t._self._c||a;return v("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[v("h2",{attrs:{id:"什么是fizz网关"}},[v("a",{staticClass:"header-anchor",attrs:{href:"#什么是fizz网关"}},[t._v("#")]),t._v(" 什么是Fizz网关")]),t._v(" "),v("p",[t._v("A Managerment API Gateway in Java . Fizz Gateway 是一个基于 Java开发的微服务网关,能够实现热服务编排、自动授权选择、线上服务脚本编码、在线测试、高性能路由、API审核管理等目的,拥有强大的自定义插件系统可以自行扩展,并且提供友好的图形化配置界面,能够快速帮助企业进行API服务治理、减少中间层胶水代码以及降低编码投入、提高 API 服务的稳定性和安全性。")]),t._v(" "),v("h2",{attrs:{id:"fizz的设计"}},[v("a",{staticClass:"header-anchor",attrs:{href:"#fizz的设计"}},[t._v("#")]),t._v(" Fizz的设计")]),t._v(" "),v("p",[v("img",{attrs:{src:"/fizz_design.png",alt:""}})]),t._v(" "),v("h2",{attrs:{id:"产品特性"}},[v("a",{staticClass:"header-anchor",attrs:{href:"#产品特性"}},[t._v("#")]),t._v(" 产品特性")]),t._v(" "),v("ul",[v("li",[t._v("集群管理:Fizz网关节点是无状态的,配置信息自动同步,支持节点水平拓展和多集群部署。")]),t._v(" "),v("li",[t._v("服务编排:支持热服务编排能力,支持前后端编码,随时随地更新API。")]),t._v(" "),v("li",[t._v("负载均衡:支持round-robin负载均衡。")]),t._v(" "),v("li",[t._v("服务发现:支持从Eureka注册中心发现后端服务器。")]),t._v(" "),v("li",[t._v("配置中心:支持接入apollo配置中心。")]),t._v(" "),v("li",[t._v("HTTP反向代理:隐藏真实后端服务,支持 Rest API反向代理。")]),t._v(" "),v("li",[t._v("访问策略:支持不同策略访问不同的API、配置不同的鉴权等。")]),t._v(" "),v("li",[t._v("IP黑白名单:支持配置IP黑白名单。")]),t._v(" "),v("li",[t._v("自定义插件:强大的插件机制支持自由扩展。")]),t._v(" "),v("li",[t._v("可扩展:简单易用的插件机制方便扩展功能。")]),t._v(" "),v("li",[t._v("高性能:性能在众多网关之中表现优异。")]),t._v(" "),v("li",[t._v("版本控制:支持操作的发布和多次回滚。")]),t._v(" "),v("li",[t._v("管理后台:通过管理后台界面对网关集群进行各项配置。")])])])}),[],!1,null,null,null);a.default=_.exports}}]); \ No newline at end of file diff --git a/docs/assets/js/15.791d6b9d.js b/docs/assets/js/15.0358b10e.js similarity index 96% rename from docs/assets/js/15.791d6b9d.js rename to docs/assets/js/15.0358b10e.js index 00c65dc..75de6b9 100644 --- a/docs/assets/js/15.791d6b9d.js +++ b/docs/assets/js/15.0358b10e.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[15],{360:function(a,r,t){"use strict";t.r(r);var e=t(42),_=Object(e.a)({},(function(){var a=this,r=a.$createElement,t=a._self._c||r;return t("ContentSlotsDistributor",{attrs:{"slot-key":a.$parent.slotKey}},[t("h2",{attrs:{id:"概述"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#概述"}},[a._v("#")]),a._v(" 概述")]),a._v(" "),t("p",[a._v("聚合接口的发布|下线操作需要提交发布|下线申请,审核通过后申请人才能执行发布|下线操作。待审核功能用于审核发布|下线申请,下面介绍待审核功能。")]),a._v(" "),t("h2",{attrs:{id:"审核列表"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#审核列表"}},[a._v("#")]),a._v(" 审核列表")]),a._v(" "),t("p",[a._v("菜单位置:发布申请 > 待审核。点击菜单后进入审核列表页面,如图所示。")]),a._v(" "),t("p",[t("img",{attrs:{src:"/manager_aggregate_approve_list_query.png",alt:"manager_aggregate_approve_list_query"}})]),a._v(" "),t("h2",{attrs:{id:"审核操作"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#审核操作"}},[a._v("#")]),a._v(" 审核操作")]),a._v(" "),t("p",[a._v("点击 查看 按钮可以查看发布|下线申请详情,详情页中可执行审核操作。")]),a._v(" "),t("p",[a._v("申请列表页提供快速审核操作,点击 审核 按钮后弹出审核确认窗口,如图所示。")]),a._v(" "),t("p",[t("img",{attrs:{src:"/manager_aggregate_approve_op_1.png",alt:"manager_aggregate_approve_op_1"}})]),a._v(" "),t("p",[t("img",{attrs:{src:"/manager_aggregate_approve_op_2.png",alt:"manager_aggregate_approve_op_2"}})]),a._v(" "),t("p",[a._v("审核结果:勾选通过,审核后申请能可执行申请的操作;勾选不通过,审核后申请失败,申请人不能执行申请的操作。")]),a._v(" "),t("p",[a._v("审核后申请人会收到审核结果邮件通知,如下图是审核通过的邮件通知。")]),a._v(" "),t("p",[t("img",{attrs:{src:"/manager_aggregate_approve_op_3.png",alt:"manager_aggregate_approve_op_3"}})])])}),[],!1,null,null,null);r.default=_.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[15],{359:function(a,r,t){"use strict";t.r(r);var e=t(42),_=Object(e.a)({},(function(){var a=this,r=a.$createElement,t=a._self._c||r;return t("ContentSlotsDistributor",{attrs:{"slot-key":a.$parent.slotKey}},[t("h2",{attrs:{id:"概述"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#概述"}},[a._v("#")]),a._v(" 概述")]),a._v(" "),t("p",[a._v("聚合接口的发布|下线操作需要提交发布|下线申请,审核通过后申请人才能执行发布|下线操作。待审核功能用于审核发布|下线申请,下面介绍待审核功能。")]),a._v(" "),t("h2",{attrs:{id:"审核列表"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#审核列表"}},[a._v("#")]),a._v(" 审核列表")]),a._v(" "),t("p",[a._v("菜单位置:发布申请 > 待审核。点击菜单后进入审核列表页面,如图所示。")]),a._v(" "),t("p",[t("img",{attrs:{src:"/manager_aggregate_approve_list_query.png",alt:"manager_aggregate_approve_list_query"}})]),a._v(" "),t("h2",{attrs:{id:"审核操作"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#审核操作"}},[a._v("#")]),a._v(" 审核操作")]),a._v(" "),t("p",[a._v("点击 查看 按钮可以查看发布|下线申请详情,详情页中可执行审核操作。")]),a._v(" "),t("p",[a._v("申请列表页提供快速审核操作,点击 审核 按钮后弹出审核确认窗口,如图所示。")]),a._v(" "),t("p",[t("img",{attrs:{src:"/manager_aggregate_approve_op_1.png",alt:"manager_aggregate_approve_op_1"}})]),a._v(" "),t("p",[t("img",{attrs:{src:"/manager_aggregate_approve_op_2.png",alt:"manager_aggregate_approve_op_2"}})]),a._v(" "),t("p",[a._v("审核结果:勾选通过,审核后申请能可执行申请的操作;勾选不通过,审核后申请失败,申请人不能执行申请的操作。")]),a._v(" "),t("p",[a._v("审核后申请人会收到审核结果邮件通知,如下图是审核通过的邮件通知。")]),a._v(" "),t("p",[t("img",{attrs:{src:"/manager_aggregate_approve_op_3.png",alt:"manager_aggregate_approve_op_3"}})])])}),[],!1,null,null,null);r.default=_.exports}}]); \ No newline at end of file diff --git a/docs/assets/js/16.4ae255f1.js b/docs/assets/js/16.f0131aa9.js similarity index 95% rename from docs/assets/js/16.4ae255f1.js rename to docs/assets/js/16.f0131aa9.js index 3542d1e..6d38023 100644 --- a/docs/assets/js/16.4ae255f1.js +++ b/docs/assets/js/16.f0131aa9.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[16],{358:function(a,t,e){"use strict";e.r(t);var _=e(42),r=Object(_.a)({},(function(){var a=this,t=a.$createElement,e=a._self._c||t;return e("ContentSlotsDistributor",{attrs:{"slot-key":a.$parent.slotKey}},[e("h2",{attrs:{id:"概述"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#概述"}},[a._v("#")]),a._v(" 概述")]),a._v(" "),e("p",[a._v("管理后台记录了发布|下线申请的审核操作日志,审核日志功能提供界面查询后台记录的审核操作日志。")]),a._v(" "),e("h2",{attrs:{id:"审核日志列表"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#审核日志列表"}},[a._v("#")]),a._v(" 审核日志列表")]),a._v(" "),e("p",[a._v("菜单位置:发布申请 > 审核日志。点击菜单后进入审核日志列表页面,如图所示。")]),a._v(" "),e("p",[e("img",{attrs:{src:"/manager_aggregate_approve_op_log_list_query.png",alt:"manager_aggregate_approve_op_log_list_query"}})]),a._v(" "),e("h2",{attrs:{id:"审核日志详情"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#审核日志详情"}},[a._v("#")]),a._v(" 审核日志详情")]),a._v(" "),e("p",[a._v("点击 查看 按钮弹出审核日志详情页面,如图所示。")]),a._v(" "),e("p",[e("img",{attrs:{src:"/manager_aggregate_approve_op_log_detail_1.png",alt:"manager_aggregate_approve_op_log_detail_1"}})]),a._v(" "),e("p",[e("img",{attrs:{src:"/manager_aggregate_approve_op_log_detail_2.png",alt:"manager_aggregate_approve_op_log_detail_2"}})])])}),[],!1,null,null,null);t.default=r.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[16],{362:function(a,t,e){"use strict";e.r(t);var _=e(42),r=Object(_.a)({},(function(){var a=this,t=a.$createElement,e=a._self._c||t;return e("ContentSlotsDistributor",{attrs:{"slot-key":a.$parent.slotKey}},[e("h2",{attrs:{id:"概述"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#概述"}},[a._v("#")]),a._v(" 概述")]),a._v(" "),e("p",[a._v("管理后台记录了发布|下线申请的审核操作日志,审核日志功能提供界面查询后台记录的审核操作日志。")]),a._v(" "),e("h2",{attrs:{id:"审核日志列表"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#审核日志列表"}},[a._v("#")]),a._v(" 审核日志列表")]),a._v(" "),e("p",[a._v("菜单位置:发布申请 > 审核日志。点击菜单后进入审核日志列表页面,如图所示。")]),a._v(" "),e("p",[e("img",{attrs:{src:"/manager_aggregate_approve_op_log_list_query.png",alt:"manager_aggregate_approve_op_log_list_query"}})]),a._v(" "),e("h2",{attrs:{id:"审核日志详情"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#审核日志详情"}},[a._v("#")]),a._v(" 审核日志详情")]),a._v(" "),e("p",[a._v("点击 查看 按钮弹出审核日志详情页面,如图所示。")]),a._v(" "),e("p",[e("img",{attrs:{src:"/manager_aggregate_approve_op_log_detail_1.png",alt:"manager_aggregate_approve_op_log_detail_1"}})]),a._v(" "),e("p",[e("img",{attrs:{src:"/manager_aggregate_approve_op_log_detail_2.png",alt:"manager_aggregate_approve_op_log_detail_2"}})])])}),[],!1,null,null,null);t.default=r.exports}}]); \ No newline at end of file diff --git a/docs/assets/js/17.32fa8ea0.js b/docs/assets/js/17.53dd322c.js similarity index 98% rename from docs/assets/js/17.32fa8ea0.js rename to docs/assets/js/17.53dd322c.js index ceb5daa..3ae508e 100644 --- a/docs/assets/js/17.32fa8ea0.js +++ b/docs/assets/js/17.53dd322c.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[17],{362:function(a,_,e){"use strict";e.r(_);var g=e(42),t=Object(g.a)({},(function(){var a=this,_=a.$createElement,e=a._self._c||_;return e("ContentSlotsDistributor",{attrs:{"slot-key":a.$parent.slotKey}},[e("h2",{attrs:{id:"概述"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#概述"}},[a._v("#")]),a._v(" 概述")]),a._v(" "),e("p",[a._v("聚合接口的发布|下线操作需要提交发布|下线申请,审核通过后申请人才能执行发布|下线操作。我的申请功能用于发布|下线申请过程的相关操作,下面介绍我的申请功能。")]),a._v(" "),e("h2",{attrs:{id:"申请列表"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#申请列表"}},[a._v("#")]),a._v(" 申请列表")]),a._v(" "),e("p",[a._v("菜单位置:发布申请 > 我的申请。点击菜单后进入申请列表页面,如图所示。")]),a._v(" "),e("p",[e("img",{attrs:{src:"/manager_aggregate_my_apply_list_query.png",alt:"manager_aggregate_my_apply_list_query"}})]),a._v(" "),e("h2",{attrs:{id:"申请撤回"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#申请撤回"}},[a._v("#")]),a._v(" 申请撤回")]),a._v(" "),e("p",[a._v("对于已提交但未被审核的申请可执行撤回操作,点击 撤回 按钮弹出确认窗口,如图所示。")]),a._v(" "),e("p",[e("img",{attrs:{src:"/manager_aggregate_my_apply_revoke_1.png",alt:"manager_aggregate_my_apply_revoke_1"}})]),a._v(" "),e("p",[a._v("点击 确定 按钮后确认撤回申请,如图所示。")]),a._v(" "),e("p",[e("img",{attrs:{src:"/manager_aggregate_my_apply_revoke_2.png",alt:"manager_aggregate_my_apply_revoke_2"}})]),a._v(" "),e("p",[a._v("撤回后审核人会收到邮箱提醒无需再处理该申请,如图所示。")]),a._v(" "),e("p",[e("img",{attrs:{src:"/manager_aggregate_my_apply_revoke_3.png",alt:"manager_aggregate_my_apply_revoke_3"}})]),a._v(" "),e("p",[a._v("撤回后可对申请重新进行编辑后再次提交,点击 编辑 按钮后弹出编辑窗口,如图所示。")]),a._v(" "),e("p",[e("img",{attrs:{src:"/manager_aggregate_my_apply_revoke_4.png",alt:"manager_aggregate_my_apply_revoke_4"}})]),a._v(" "),e("p",[a._v("点击 确定 按钮后再次提交申请,如图所示。")]),a._v(" "),e("p",[e("img",{attrs:{src:"/manager_aggregate_my_apply_revoke_5.png",alt:"manager_aggregate_my_apply_revoke_5"}})]),a._v(" "),e("h2",{attrs:{id:"申请详情"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#申请详情"}},[a._v("#")]),a._v(" 申请详情")]),a._v(" "),e("p",[a._v("点击 查看 按钮查看申请详情。")]),a._v(" "),e("p",[e("img",{attrs:{src:"/manager_aggregate_my_apply_detail_1.png",alt:"manager_aggregate_my_apply_detail_1"}})]),a._v(" "),e("p",[e("img",{attrs:{src:"/manager_aggregate_my_apply_detail_2.png",alt:"manager_aggregate_my_apply_detail_2"}})]),a._v(" "),e("p",[a._v("操作日志记录该申请的所有操作,包括申请提交、申请撤回、申请重新提交、审核不通过、审核通过、修改审核人、接口发布、接口下线 、接口回滚、接口撤回。")]),a._v(" "),e("p",[a._v("待审核状态申请可以更换审核人,点击 修改审核人 按钮后弹出修改审核人窗口,如图所示。")]),a._v(" "),e("p",[e("img",{attrs:{src:"/manager_aggregate_my_apply_detail_3.png",alt:"manager_aggregate_my_apply_detail_3"}})]),a._v(" "),e("p",[a._v("重新选择审核人后点击 确定 按钮,修改审核人完成。")]),a._v(" "),e("p",[a._v("修改后原审核人会收到邮件提醒无须再处理该申请。")]),a._v(" "),e("p",[a._v("修改后新的审核人会收到邮件提醒需要处理该申请。")]),a._v(" "),e("p",[a._v("审核通过后可以对接口进行发布操作,如图所示。")]),a._v(" "),e("p",[e("img",{attrs:{src:"/manager_aggregate_my_apply_detail_4.png",alt:"manager_aggregate_my_apply_detail_4"}})]),a._v(" "),e("p",[a._v("批量发布:对申请内的接口批量发布推送到Fizz网关。")]),a._v(" "),e("p",[a._v("批量回滚:对申请内的接口批量回滚到上一个版本,当发布后接口异常时该操作相当有用。")]),a._v(" "),e("p",[a._v("对于申请通过后又无须操作的接口可以执行撤回操作,撤回接口时必须填写备注信息用于回溯查询,如图所示。")]),a._v(" "),e("p",[e("img",{attrs:{src:"/manager_aggregate_my_apply_detail_5.png",alt:"manager_aggregate_my_apply_detail_5"}})]),a._v(" "),e("p",[e("img",{attrs:{src:"/manager_aggregate_my_apply_detail_6.png",alt:"manager_aggregate_my_apply_detail_6"}})])])}),[],!1,null,null,null);_.default=t.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[17],{360:function(a,_,e){"use strict";e.r(_);var g=e(42),t=Object(g.a)({},(function(){var a=this,_=a.$createElement,e=a._self._c||_;return e("ContentSlotsDistributor",{attrs:{"slot-key":a.$parent.slotKey}},[e("h2",{attrs:{id:"概述"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#概述"}},[a._v("#")]),a._v(" 概述")]),a._v(" "),e("p",[a._v("聚合接口的发布|下线操作需要提交发布|下线申请,审核通过后申请人才能执行发布|下线操作。我的申请功能用于发布|下线申请过程的相关操作,下面介绍我的申请功能。")]),a._v(" "),e("h2",{attrs:{id:"申请列表"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#申请列表"}},[a._v("#")]),a._v(" 申请列表")]),a._v(" "),e("p",[a._v("菜单位置:发布申请 > 我的申请。点击菜单后进入申请列表页面,如图所示。")]),a._v(" "),e("p",[e("img",{attrs:{src:"/manager_aggregate_my_apply_list_query.png",alt:"manager_aggregate_my_apply_list_query"}})]),a._v(" "),e("h2",{attrs:{id:"申请撤回"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#申请撤回"}},[a._v("#")]),a._v(" 申请撤回")]),a._v(" "),e("p",[a._v("对于已提交但未被审核的申请可执行撤回操作,点击 撤回 按钮弹出确认窗口,如图所示。")]),a._v(" "),e("p",[e("img",{attrs:{src:"/manager_aggregate_my_apply_revoke_1.png",alt:"manager_aggregate_my_apply_revoke_1"}})]),a._v(" "),e("p",[a._v("点击 确定 按钮后确认撤回申请,如图所示。")]),a._v(" "),e("p",[e("img",{attrs:{src:"/manager_aggregate_my_apply_revoke_2.png",alt:"manager_aggregate_my_apply_revoke_2"}})]),a._v(" "),e("p",[a._v("撤回后审核人会收到邮箱提醒无需再处理该申请,如图所示。")]),a._v(" "),e("p",[e("img",{attrs:{src:"/manager_aggregate_my_apply_revoke_3.png",alt:"manager_aggregate_my_apply_revoke_3"}})]),a._v(" "),e("p",[a._v("撤回后可对申请重新进行编辑后再次提交,点击 编辑 按钮后弹出编辑窗口,如图所示。")]),a._v(" "),e("p",[e("img",{attrs:{src:"/manager_aggregate_my_apply_revoke_4.png",alt:"manager_aggregate_my_apply_revoke_4"}})]),a._v(" "),e("p",[a._v("点击 确定 按钮后再次提交申请,如图所示。")]),a._v(" "),e("p",[e("img",{attrs:{src:"/manager_aggregate_my_apply_revoke_5.png",alt:"manager_aggregate_my_apply_revoke_5"}})]),a._v(" "),e("h2",{attrs:{id:"申请详情"}},[e("a",{staticClass:"header-anchor",attrs:{href:"#申请详情"}},[a._v("#")]),a._v(" 申请详情")]),a._v(" "),e("p",[a._v("点击 查看 按钮查看申请详情。")]),a._v(" "),e("p",[e("img",{attrs:{src:"/manager_aggregate_my_apply_detail_1.png",alt:"manager_aggregate_my_apply_detail_1"}})]),a._v(" "),e("p",[e("img",{attrs:{src:"/manager_aggregate_my_apply_detail_2.png",alt:"manager_aggregate_my_apply_detail_2"}})]),a._v(" "),e("p",[a._v("操作日志记录该申请的所有操作,包括申请提交、申请撤回、申请重新提交、审核不通过、审核通过、修改审核人、接口发布、接口下线 、接口回滚、接口撤回。")]),a._v(" "),e("p",[a._v("待审核状态申请可以更换审核人,点击 修改审核人 按钮后弹出修改审核人窗口,如图所示。")]),a._v(" "),e("p",[e("img",{attrs:{src:"/manager_aggregate_my_apply_detail_3.png",alt:"manager_aggregate_my_apply_detail_3"}})]),a._v(" "),e("p",[a._v("重新选择审核人后点击 确定 按钮,修改审核人完成。")]),a._v(" "),e("p",[a._v("修改后原审核人会收到邮件提醒无须再处理该申请。")]),a._v(" "),e("p",[a._v("修改后新的审核人会收到邮件提醒需要处理该申请。")]),a._v(" "),e("p",[a._v("审核通过后可以对接口进行发布操作,如图所示。")]),a._v(" "),e("p",[e("img",{attrs:{src:"/manager_aggregate_my_apply_detail_4.png",alt:"manager_aggregate_my_apply_detail_4"}})]),a._v(" "),e("p",[a._v("批量发布:对申请内的接口批量发布推送到Fizz网关。")]),a._v(" "),e("p",[a._v("批量回滚:对申请内的接口批量回滚到上一个版本,当发布后接口异常时该操作相当有用。")]),a._v(" "),e("p",[a._v("对于申请通过后又无须操作的接口可以执行撤回操作,撤回接口时必须填写备注信息用于回溯查询,如图所示。")]),a._v(" "),e("p",[e("img",{attrs:{src:"/manager_aggregate_my_apply_detail_5.png",alt:"manager_aggregate_my_apply_detail_5"}})]),a._v(" "),e("p",[e("img",{attrs:{src:"/manager_aggregate_my_apply_detail_6.png",alt:"manager_aggregate_my_apply_detail_6"}})])])}),[],!1,null,null,null);_.default=t.exports}}]); \ No newline at end of file diff --git a/docs/assets/js/21.081e4e30.js b/docs/assets/js/21.dca6f5c4.js similarity index 97% rename from docs/assets/js/21.081e4e30.js rename to docs/assets/js/21.dca6f5c4.js index 60dba6b..d131c88 100644 --- a/docs/assets/js/21.081e4e30.js +++ b/docs/assets/js/21.dca6f5c4.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[21],{368:function(a,e,t){"use strict";t.r(e);var _=t(42),r=Object(_.a)({},(function(){var a=this,e=a.$createElement,t=a._self._c||e;return t("ContentSlotsDistributor",{attrs:{"slot-key":a.$parent.slotKey}},[t("h2",{attrs:{id:"概述"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#概述"}},[a._v("#")]),a._v(" 概述")]),a._v(" "),t("p",[a._v("网关缓存功能用于查询Fizz网关实例本地缓存的已发布接口信息,可以快速的了解当前网关实例生效的全部接口,同时通过查看后台接口发布版本号与网关实例本地缓存的接口版本号是否一致可以排查接口缓存问题,下面介绍网关缓存功能的操作。")]),a._v(" "),t("h2",{attrs:{id:"网关列表"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#网关列表"}},[a._v("#")]),a._v(" 网关列表")]),a._v(" "),t("p",[a._v("菜单位置:服务编排 > 网关缓存。点击菜单后进入网关列表页面,如图所示。")]),a._v(" "),t("p",[t("img",{attrs:{src:"/manager_aggregate_gateway_list_query.png",alt:"manager_aggregate_gateway_list_query"}})]),a._v(" "),t("p",[a._v("Fizz网关与后台注册到同一个eureka注册中心,后台通过eureka获取网关的实例列表。")]),a._v(" "),t("h2",{attrs:{id:"网关缓存列表"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#网关缓存列表"}},[a._v("#")]),a._v(" 网关缓存列表")]),a._v(" "),t("p",[a._v("点击 查看 按钮后弹出网关详情页面,该页面显示所选网关实例的接口缓存列表,如图所示。")]),a._v(" "),t("p",[t("img",{attrs:{src:"/manager_aggregate_gateway_cache_list_query_1.png",alt:"manager_aggregate_gateway_cache_list_query_1"}})]),a._v(" "),t("p",[t("img",{attrs:{src:"/manager_aggregate_gateway_cache_list_query_2.png",alt:"manager_aggregate_gateway_cache_list_query_2"}})]),a._v(" "),t("h2",{attrs:{id:"网关缓存详情"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#网关缓存详情"}},[a._v("#")]),a._v(" 网关缓存详情")]),a._v(" "),t("p",[a._v("点击 查看 按钮弹出所选接口的配置详情,如图所示。")]),a._v(" "),t("p",[t("img",{attrs:{src:"/manager_aggregate_gateway_cache_detail_1.png",alt:"manager_aggregate_gateway_cache_detail_1"}})]),a._v(" "),t("p",[t("img",{attrs:{src:"/manager_aggregate_gateway_cache_detail_2.png",alt:"manager_aggregate_gateway_cache_detail_2"}})])])}),[],!1,null,null,null);e.default=r.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[21],{367:function(a,e,t){"use strict";t.r(e);var _=t(42),r=Object(_.a)({},(function(){var a=this,e=a.$createElement,t=a._self._c||e;return t("ContentSlotsDistributor",{attrs:{"slot-key":a.$parent.slotKey}},[t("h2",{attrs:{id:"概述"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#概述"}},[a._v("#")]),a._v(" 概述")]),a._v(" "),t("p",[a._v("网关缓存功能用于查询Fizz网关实例本地缓存的已发布接口信息,可以快速的了解当前网关实例生效的全部接口,同时通过查看后台接口发布版本号与网关实例本地缓存的接口版本号是否一致可以排查接口缓存问题,下面介绍网关缓存功能的操作。")]),a._v(" "),t("h2",{attrs:{id:"网关列表"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#网关列表"}},[a._v("#")]),a._v(" 网关列表")]),a._v(" "),t("p",[a._v("菜单位置:服务编排 > 网关缓存。点击菜单后进入网关列表页面,如图所示。")]),a._v(" "),t("p",[t("img",{attrs:{src:"/manager_aggregate_gateway_list_query.png",alt:"manager_aggregate_gateway_list_query"}})]),a._v(" "),t("p",[a._v("Fizz网关与后台注册到同一个eureka注册中心,后台通过eureka获取网关的实例列表。")]),a._v(" "),t("h2",{attrs:{id:"网关缓存列表"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#网关缓存列表"}},[a._v("#")]),a._v(" 网关缓存列表")]),a._v(" "),t("p",[a._v("点击 查看 按钮后弹出网关详情页面,该页面显示所选网关实例的接口缓存列表,如图所示。")]),a._v(" "),t("p",[t("img",{attrs:{src:"/manager_aggregate_gateway_cache_list_query_1.png",alt:"manager_aggregate_gateway_cache_list_query_1"}})]),a._v(" "),t("p",[t("img",{attrs:{src:"/manager_aggregate_gateway_cache_list_query_2.png",alt:"manager_aggregate_gateway_cache_list_query_2"}})]),a._v(" "),t("h2",{attrs:{id:"网关缓存详情"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#网关缓存详情"}},[a._v("#")]),a._v(" 网关缓存详情")]),a._v(" "),t("p",[a._v("点击 查看 按钮弹出所选接口的配置详情,如图所示。")]),a._v(" "),t("p",[t("img",{attrs:{src:"/manager_aggregate_gateway_cache_detail_1.png",alt:"manager_aggregate_gateway_cache_detail_1"}})]),a._v(" "),t("p",[t("img",{attrs:{src:"/manager_aggregate_gateway_cache_detail_2.png",alt:"manager_aggregate_gateway_cache_detail_2"}})])])}),[],!1,null,null,null);e.default=r.exports}}]); \ No newline at end of file diff --git a/docs/assets/js/22.0c08546e.js b/docs/assets/js/22.db62cc12.js similarity index 98% rename from docs/assets/js/22.0c08546e.js rename to docs/assets/js/22.db62cc12.js index 7325cbd..60bd5b1 100644 --- a/docs/assets/js/22.0c08546e.js +++ b/docs/assets/js/22.db62cc12.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[22],{367:function(_,a,t){"use strict";t.r(a);var r=t(42),e=Object(r.a)({},(function(){var _=this,a=_.$createElement,t=_._self._c||a;return t("ContentSlotsDistributor",{attrs:{"slot-key":_.$parent.slotKey}},[t("h2",{attrs:{id:"概述"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#概述"}},[_._v("#")]),_._v(" 概述")]),_._v(" "),t("p",[_._v("网关分组功能用于维护分组元数据,将网关实例IP与分组关联,通过为不同的分组配置不同的路由策略,从而实现网关的分组管理。")]),_._v(" "),t("h2",{attrs:{id:"分组示例"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#分组示例"}},[_._v("#")]),_._v(" 分组示例")]),_._v(" "),t("p",[_._v("我们的线上业务涉及To C(个人用户)、To B(企业)、To T(第三方),对于不同业务会有对应的机器接受请求访问,不同的业务需要有各自的路由策略,因此进行了如下的分组划分。")]),_._v(" "),t("table",[t("thead",[t("tr",[t("th",[_._v("分组ID")]),_._v(" "),t("th",[_._v("分组名称")]),_._v(" "),t("th",[_._v("描述")])])]),_._v(" "),t("tbody",[t("tr",[t("td",[_._v("default")]),_._v(" "),t("td",[_._v("默认分组")]),_._v(" "),t("td",[_._v("默认分组是后台默认创建的分组,不用指定IP,不属于其它分组的机器都归到默认分组,默认分组不可修改或删除")])]),_._v(" "),t("tr",[t("td",[_._v("c")]),_._v(" "),t("td",[_._v("2c分组")]),_._v(" "),t("td",[_._v("只接受面向个人用户的请求")])]),_._v(" "),t("tr",[t("td",[_._v("b")]),_._v(" "),t("td",[_._v("2b分组")]),_._v(" "),t("td",[_._v("只接受面向企业的请求")])]),_._v(" "),t("tr",[t("td",[_._v("t")]),_._v(" "),t("td",[_._v("面向第三方的分组")]),_._v(" "),t("td",[_._v("只接受面向第三方的请求")])])])]),_._v(" "),t("p",[_._v("下面介绍网关分组功能的操作。")]),_._v(" "),t("h2",{attrs:{id:"分组列表"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#分组列表"}},[_._v("#")]),_._v(" 分组列表")]),_._v(" "),t("p",[_._v("菜单位置:网关管理 > 网关分组。点击菜单后进入分组列表页面,如图所示。")]),_._v(" "),t("p",[t("img",{attrs:{src:"/manager_gateway_group_list_query.png",alt:"manager_gateway_group_list_query"}})]),_._v(" "),t("h2",{attrs:{id:"新增分组"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#新增分组"}},[_._v("#")]),_._v(" 新增分组")]),_._v(" "),t("p",[_._v("点击 新增 按钮弹出新增窗口,如图所示。")]),_._v(" "),t("p",[t("img",{attrs:{src:"/manager_gateway_group_add_1.png",alt:"manager_gateway_group_add_1"}})]),_._v(" "),t("p",[t("img",{attrs:{src:"/manager_gateway_group_add_2.png",alt:"manager_gateway_group_add_2"}})]),_._v(" "),t("p",[_._v("分组ID:分组的唯一标识,长度不能超过32个字符,必填;")]),_._v(" "),t("p",[_._v("分组名称:分组的名称,用于在分组选项时展示,长度不能超过32个字符,必填;")]),_._v(" "),t("p",[_._v("网关实例IP:Fizz网关集群内的机器IP地址,多个IP地址使用逗号分隔。")]),_._v(" "),t("h2",{attrs:{id:"编辑分组"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#编辑分组"}},[_._v("#")]),_._v(" 编辑分组")]),_._v(" "),t("p",[_._v("点击 编辑 按钮弹出编辑窗口,如图所示。")]),_._v(" "),t("p",[t("img",{attrs:{src:"/manager_gateway_group_edit_1.png",alt:"manager_gateway_group_edit_1"}})]),_._v(" "),t("p",[t("img",{attrs:{src:"/manager_gateway_group_edit_2.png",alt:"manager_gateway_group_edit_2"}})]),_._v(" "),t("h2",{attrs:{id:"删除分组"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#删除分组"}},[_._v("#")]),_._v(" 删除分组")]),_._v(" "),t("p",[_._v("点击 删除 按钮弹出删除确认窗口,如图所示。")]),_._v(" "),t("p",[t("img",{attrs:{src:"/manager_gateway_group_delete_1.png",alt:"manager_gateway_group_delete_1"}})]),_._v(" "),t("p",[t("img",{attrs:{src:"/manager_gateway_group_delete_2.png",alt:"manager_gateway_group_delete_2"}})]),_._v(" "),t("p",[_._v("点击 确定 按钮后删除网关分组,如果网关分组存在关联的路由配置时,需要将关联的路由配置全部删除后才能删除分组。")])])}),[],!1,null,null,null);a.default=e.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[22],{368:function(_,a,t){"use strict";t.r(a);var r=t(42),e=Object(r.a)({},(function(){var _=this,a=_.$createElement,t=_._self._c||a;return t("ContentSlotsDistributor",{attrs:{"slot-key":_.$parent.slotKey}},[t("h2",{attrs:{id:"概述"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#概述"}},[_._v("#")]),_._v(" 概述")]),_._v(" "),t("p",[_._v("网关分组功能用于维护分组元数据,将网关实例IP与分组关联,通过为不同的分组配置不同的路由策略,从而实现网关的分组管理。")]),_._v(" "),t("h2",{attrs:{id:"分组示例"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#分组示例"}},[_._v("#")]),_._v(" 分组示例")]),_._v(" "),t("p",[_._v("我们的线上业务涉及To C(个人用户)、To B(企业)、To T(第三方),对于不同业务会有对应的机器接受请求访问,不同的业务需要有各自的路由策略,因此进行了如下的分组划分。")]),_._v(" "),t("table",[t("thead",[t("tr",[t("th",[_._v("分组ID")]),_._v(" "),t("th",[_._v("分组名称")]),_._v(" "),t("th",[_._v("描述")])])]),_._v(" "),t("tbody",[t("tr",[t("td",[_._v("default")]),_._v(" "),t("td",[_._v("默认分组")]),_._v(" "),t("td",[_._v("默认分组是后台默认创建的分组,不用指定IP,不属于其它分组的机器都归到默认分组,默认分组不可修改或删除")])]),_._v(" "),t("tr",[t("td",[_._v("c")]),_._v(" "),t("td",[_._v("2c分组")]),_._v(" "),t("td",[_._v("只接受面向个人用户的请求")])]),_._v(" "),t("tr",[t("td",[_._v("b")]),_._v(" "),t("td",[_._v("2b分组")]),_._v(" "),t("td",[_._v("只接受面向企业的请求")])]),_._v(" "),t("tr",[t("td",[_._v("t")]),_._v(" "),t("td",[_._v("面向第三方的分组")]),_._v(" "),t("td",[_._v("只接受面向第三方的请求")])])])]),_._v(" "),t("p",[_._v("下面介绍网关分组功能的操作。")]),_._v(" "),t("h2",{attrs:{id:"分组列表"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#分组列表"}},[_._v("#")]),_._v(" 分组列表")]),_._v(" "),t("p",[_._v("菜单位置:网关管理 > 网关分组。点击菜单后进入分组列表页面,如图所示。")]),_._v(" "),t("p",[t("img",{attrs:{src:"/manager_gateway_group_list_query.png",alt:"manager_gateway_group_list_query"}})]),_._v(" "),t("h2",{attrs:{id:"新增分组"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#新增分组"}},[_._v("#")]),_._v(" 新增分组")]),_._v(" "),t("p",[_._v("点击 新增 按钮弹出新增窗口,如图所示。")]),_._v(" "),t("p",[t("img",{attrs:{src:"/manager_gateway_group_add_1.png",alt:"manager_gateway_group_add_1"}})]),_._v(" "),t("p",[t("img",{attrs:{src:"/manager_gateway_group_add_2.png",alt:"manager_gateway_group_add_2"}})]),_._v(" "),t("p",[_._v("分组ID:分组的唯一标识,长度不能超过32个字符,必填;")]),_._v(" "),t("p",[_._v("分组名称:分组的名称,用于在分组选项时展示,长度不能超过32个字符,必填;")]),_._v(" "),t("p",[_._v("网关实例IP:Fizz网关集群内的机器IP地址,多个IP地址使用逗号分隔。")]),_._v(" "),t("h2",{attrs:{id:"编辑分组"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#编辑分组"}},[_._v("#")]),_._v(" 编辑分组")]),_._v(" "),t("p",[_._v("点击 编辑 按钮弹出编辑窗口,如图所示。")]),_._v(" "),t("p",[t("img",{attrs:{src:"/manager_gateway_group_edit_1.png",alt:"manager_gateway_group_edit_1"}})]),_._v(" "),t("p",[t("img",{attrs:{src:"/manager_gateway_group_edit_2.png",alt:"manager_gateway_group_edit_2"}})]),_._v(" "),t("h2",{attrs:{id:"删除分组"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#删除分组"}},[_._v("#")]),_._v(" 删除分组")]),_._v(" "),t("p",[_._v("点击 删除 按钮弹出删除确认窗口,如图所示。")]),_._v(" "),t("p",[t("img",{attrs:{src:"/manager_gateway_group_delete_1.png",alt:"manager_gateway_group_delete_1"}})]),_._v(" "),t("p",[t("img",{attrs:{src:"/manager_gateway_group_delete_2.png",alt:"manager_gateway_group_delete_2"}})]),_._v(" "),t("p",[_._v("点击 确定 按钮后删除网关分组,如果网关分组存在关联的路由配置时,需要将关联的路由配置全部删除后才能删除分组。")])])}),[],!1,null,null,null);a.default=e.exports}}]); \ No newline at end of file diff --git a/docs/assets/js/24.9c5c2990.js b/docs/assets/js/24.dc881ae9.js similarity index 99% rename from docs/assets/js/24.9c5c2990.js rename to docs/assets/js/24.dc881ae9.js index efe1a5d..00e6eba 100644 --- a/docs/assets/js/24.9c5c2990.js +++ b/docs/assets/js/24.dc881ae9.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[24],{372:function(t,s,a){"use strict";a.r(s);var n=a(42),r=Object(n.a)({},(function(){var t=this,s=t.$createElement,a=t._self._c||s;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("h2",{attrs:{id:"概述"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#概述"}},[t._v("#")]),t._v(" 概述")]),t._v(" "),a("p",[t._v("插件管理功能用于维护插件元数据,定义路由级别的自定义属性、插件级别的自定义配置信息。创建的插件用于路由管理设置时启用,当网关接受请求匹配路由规则时会触发启用的插件逻辑执行,插件逻辑中可获取到自定义的属性数据。")]),t._v(" "),a("h2",{attrs:{id:"插件列表"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#插件列表"}},[t._v("#")]),t._v(" 插件列表")]),t._v(" "),a("p",[t._v("菜单位置:网关管理 > 插件管理。点击菜单后进入插件管理列表页面,如图所示。")]),t._v(" "),a("p",[a("img",{attrs:{src:"/manager_plugin_list_query.png",alt:"manager_plugin_list_query"}})]),t._v(" "),a("h2",{attrs:{id:"新增插件"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#新增插件"}},[t._v("#")]),t._v(" 新增插件")]),t._v(" "),a("p",[t._v("点击 新增 按钮弹出新增窗口,如图所示。")]),t._v(" "),a("p",[a("img",{attrs:{src:"/manager_plugin_add_1.png",alt:"manager_plugin_add_1"}})]),t._v(" "),a("p",[a("img",{attrs:{src:"/manager_plugin_add_2.png",alt:"manager_plugin_add_2"}})]),t._v(" "),a("p",[t._v("插件名称:插件名称由英文字母、下划线或数字组成,不能以数字开头,长度不能超过50个字符,必填;")]),t._v(" "),a("p",[t._v("插件描述:插件的简要描述,长度不能超过50个字符,必填;")]),t._v(" "),a("p",[t._v("默认执行顺序:插件的默认执行顺序,按从小到大排序,值越小越先执行,取值范围0~255,必填;")]),t._v(" "),a("p",[t._v("表单定义:路由级别的自定义属性,在路由管理配置启用插件时前端会将表单定义转化为表单输入界面,更多信息请查看路由管理介绍。表单规范说明如下:")]),t._v(" "),a("div",{staticClass:"language-javascript extra-class"},[a("pre",{pre:!0,attrs:{class:"language-javascript"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/*\n* plugin_config_design\n* 动态插件参考结构\n* */")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("const")]),t._v(" pluginConfig "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/* 必有字段 */")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"field"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"inputVal"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"label"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"输入框"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"component"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"input"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// input, select, radio, checkbox,")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"dataType"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"string"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// number(long, double), string, boolean, array")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/* 可选字段 */")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"desc"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"字段的说明文字"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"placeholder"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"placeholder文字"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"default"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Aa123"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 初始默认值")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"options"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// for select, radio, checkbox")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"label"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"选项1"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"value"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// number(long, double), string, boolean,")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"label"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"选项2"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"value"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"rules"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// min|max / range / length / regex pattern")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"required"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("true")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"message"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"输入框不能为空"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"trigger"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"change"')]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// required 必填")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v('// { "min": 3, "ma x": 5, "message": "长度在 3 到 5 个字符", "trigger": "change" }, // range 长度范围(for dataType:"string")')]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v('// { "len": 8, "message": "长度需 8 个字符", "trigger": "change" }, // length 长度限制(for dataType:"string")')]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v('// { "type": "number", "message": "请输入数字类型"}, // for dataType:"number" 校验数值')]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v('// { "type": "integer", "message": "请输入整数数值", "trigger": "change" }, // for dataType:"long" 校验整数')]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v('// { "type": "float", "message": "请输入浮点数数值", "trigger": "change" }, // for dataType:"double" 校验浮点数')]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"pattern"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"^[A-Za-z\\\\d]+$"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"message"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"只能是字母或数字"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"trigger"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"change"')]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// regex pattern正则")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"field"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"selectVal"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"label"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"选择器"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"component"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"select"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"dataType"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"number"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"options"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"label"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"选项1"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"value"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"label"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"选项2"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"value"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"label"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"选项3"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"value"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("3")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"desc"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"选择器的说明文字"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"placeholder"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"请选择"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"rules"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"required"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("true")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"message"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"选择器不能为空"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"trigger"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"change"')]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"field"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"radioVal"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"label"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"单选框"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"component"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"radio"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"dataType"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"boolean"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"default"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("true")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"options"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"label"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"是"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"value"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("true")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"label"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"否"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"value"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("false")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"desc"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"单选框的说明文字"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"rules"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"required"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("true")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"message"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"请选择单选框"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"trigger"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"change"')]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"field"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"checkboxVal"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"label"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"多选框"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"component"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"checkbox"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"dataType"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"array"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"options"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"label"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"选项1"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"value"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("11")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"label"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"选项2"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"value"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("22")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"label"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"选项3"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"value"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("33")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"desc"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"多选框的说明文字"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"rules"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"required"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("true")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"message"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"请选择多选框"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"trigger"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"change"')]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// TODO 注意!!")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v('// 组件 "checkbox" 的dataType = "array"')]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v('// 组件 "radio/select" 的实际值类型等于options内的value值类型')]),t._v("\n")])])]),a("p",[t._v("自定义配置:插件级别的自定义配置信息,插件逻辑中可获取到该信息。")]),t._v(" "),a("h2",{attrs:{id:"编辑插件"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#编辑插件"}},[t._v("#")]),t._v(" 编辑插件")]),t._v(" "),a("p",[t._v("点击 编辑 按钮弹出编辑窗口,如图所示。")]),t._v(" "),a("p",[a("img",{attrs:{src:"/manager_plugin_edit_1.png",alt:"manager_plugin_edit_1"}})]),t._v(" "),a("p",[a("img",{attrs:{src:"/manager_plugin_edit_2.png",alt:"manager_plugin_edit_2"}})]),t._v(" "),a("h2",{attrs:{id:"删除插件"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#删除插件"}},[t._v("#")]),t._v(" 删除插件")]),t._v(" "),a("p",[t._v("点击 删除 按钮弹出删除确认窗口,如图所示。")]),t._v(" "),a("p",[a("img",{attrs:{src:"/manager_plugin_delete_1.png",alt:"manager_plugin_delete_1"}})]),t._v(" "),a("p",[a("img",{attrs:{src:"/manager_plugin_delete_2.png",alt:"manager_plugin_delete_2"}})]),t._v(" "),a("p",[t._v("点击 确定 按钮后删除插件,如果插件存在关联的路由配置时,需要将关联的路由配置全部删除后才能删除插件。")])])}),[],!1,null,null,null);s.default=r.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[24],{369:function(t,s,a){"use strict";a.r(s);var n=a(42),r=Object(n.a)({},(function(){var t=this,s=t.$createElement,a=t._self._c||s;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("h2",{attrs:{id:"概述"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#概述"}},[t._v("#")]),t._v(" 概述")]),t._v(" "),a("p",[t._v("插件管理功能用于维护插件元数据,定义路由级别的自定义属性、插件级别的自定义配置信息。创建的插件用于路由管理设置时启用,当网关接受请求匹配路由规则时会触发启用的插件逻辑执行,插件逻辑中可获取到自定义的属性数据。")]),t._v(" "),a("h2",{attrs:{id:"插件列表"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#插件列表"}},[t._v("#")]),t._v(" 插件列表")]),t._v(" "),a("p",[t._v("菜单位置:网关管理 > 插件管理。点击菜单后进入插件管理列表页面,如图所示。")]),t._v(" "),a("p",[a("img",{attrs:{src:"/manager_plugin_list_query.png",alt:"manager_plugin_list_query"}})]),t._v(" "),a("h2",{attrs:{id:"新增插件"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#新增插件"}},[t._v("#")]),t._v(" 新增插件")]),t._v(" "),a("p",[t._v("点击 新增 按钮弹出新增窗口,如图所示。")]),t._v(" "),a("p",[a("img",{attrs:{src:"/manager_plugin_add_1.png",alt:"manager_plugin_add_1"}})]),t._v(" "),a("p",[a("img",{attrs:{src:"/manager_plugin_add_2.png",alt:"manager_plugin_add_2"}})]),t._v(" "),a("p",[t._v("插件名称:插件名称由英文字母、下划线或数字组成,不能以数字开头,长度不能超过50个字符,必填;")]),t._v(" "),a("p",[t._v("插件描述:插件的简要描述,长度不能超过50个字符,必填;")]),t._v(" "),a("p",[t._v("默认执行顺序:插件的默认执行顺序,按从小到大排序,值越小越先执行,取值范围0~255,必填;")]),t._v(" "),a("p",[t._v("表单定义:路由级别的自定义属性,在路由管理配置启用插件时前端会将表单定义转化为表单输入界面,更多信息请查看路由管理介绍。表单规范说明如下:")]),t._v(" "),a("div",{staticClass:"language-javascript extra-class"},[a("pre",{pre:!0,attrs:{class:"language-javascript"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/*\n* plugin_config_design\n* 动态插件参考结构\n* */")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("const")]),t._v(" pluginConfig "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/* 必有字段 */")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"field"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"inputVal"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"label"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"输入框"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"component"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"input"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// input, select, radio, checkbox,")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"dataType"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"string"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// number(long, double), string, boolean, array")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/* 可选字段 */")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"desc"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"字段的说明文字"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"placeholder"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"placeholder文字"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"default"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"Aa123"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 初始默认值")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"options"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// for select, radio, checkbox")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"label"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"选项1"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"value"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// number(long, double), string, boolean,")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"label"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"选项2"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"value"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"rules"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// min|max / range / length / regex pattern")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"required"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("true")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"message"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"输入框不能为空"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"trigger"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"change"')]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// required 必填")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v('// { "min": 3, "ma x": 5, "message": "长度在 3 到 5 个字符", "trigger": "change" }, // range 长度范围(for dataType:"string")')]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v('// { "len": 8, "message": "长度需 8 个字符", "trigger": "change" }, // length 长度限制(for dataType:"string")')]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v('// { "type": "number", "message": "请输入数字类型"}, // for dataType:"number" 校验数值')]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v('// { "type": "integer", "message": "请输入整数数值", "trigger": "change" }, // for dataType:"long" 校验整数')]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v('// { "type": "float", "message": "请输入浮点数数值", "trigger": "change" }, // for dataType:"double" 校验浮点数')]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"pattern"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"^[A-Za-z\\\\d]+$"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"message"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"只能是字母或数字"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"trigger"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"change"')]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// regex pattern正则")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"field"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"selectVal"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"label"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"选择器"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"component"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"select"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"dataType"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"number"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"options"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"label"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"选项1"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"value"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("1")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"label"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"选项2"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"value"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("2")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"label"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"选项3"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"value"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("3")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"desc"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"选择器的说明文字"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"placeholder"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"请选择"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"rules"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"required"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("true")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"message"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"选择器不能为空"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"trigger"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"change"')]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"field"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"radioVal"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"label"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"单选框"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"component"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"radio"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"dataType"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"boolean"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"default"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("true")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"options"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"label"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"是"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"value"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("true")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"label"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"否"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"value"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("false")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"desc"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"单选框的说明文字"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"rules"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"required"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("true")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"message"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"请选择单选框"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"trigger"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"change"')]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"field"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"checkboxVal"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"label"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"多选框"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"component"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"checkbox"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"dataType"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"array"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"options"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"label"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"选项1"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"value"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("11")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"label"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"选项2"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"value"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("22")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"label"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"选项3"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"value"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("33")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"desc"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"多选框的说明文字"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"rules"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n\t "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"required"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("true")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"message"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"请选择多选框"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"trigger"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"change"')]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// TODO 注意!!")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v('// 组件 "checkbox" 的dataType = "array"')]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v('// 组件 "radio/select" 的实际值类型等于options内的value值类型')]),t._v("\n")])])]),a("p",[t._v("自定义配置:插件级别的自定义配置信息,插件逻辑中可获取到该信息。")]),t._v(" "),a("h2",{attrs:{id:"编辑插件"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#编辑插件"}},[t._v("#")]),t._v(" 编辑插件")]),t._v(" "),a("p",[t._v("点击 编辑 按钮弹出编辑窗口,如图所示。")]),t._v(" "),a("p",[a("img",{attrs:{src:"/manager_plugin_edit_1.png",alt:"manager_plugin_edit_1"}})]),t._v(" "),a("p",[a("img",{attrs:{src:"/manager_plugin_edit_2.png",alt:"manager_plugin_edit_2"}})]),t._v(" "),a("h2",{attrs:{id:"删除插件"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#删除插件"}},[t._v("#")]),t._v(" 删除插件")]),t._v(" "),a("p",[t._v("点击 删除 按钮弹出删除确认窗口,如图所示。")]),t._v(" "),a("p",[a("img",{attrs:{src:"/manager_plugin_delete_1.png",alt:"manager_plugin_delete_1"}})]),t._v(" "),a("p",[a("img",{attrs:{src:"/manager_plugin_delete_2.png",alt:"manager_plugin_delete_2"}})]),t._v(" "),a("p",[t._v("点击 确定 按钮后删除插件,如果插件存在关联的路由配置时,需要将关联的路由配置全部删除后才能删除插件。")])])}),[],!1,null,null,null);s.default=r.exports}}]); \ No newline at end of file diff --git a/docs/assets/js/25.aead8972.js b/docs/assets/js/25.bbf8bff1.js similarity index 97% rename from docs/assets/js/25.aead8972.js rename to docs/assets/js/25.bbf8bff1.js index 0256952..7f3b92c 100644 --- a/docs/assets/js/25.aead8972.js +++ b/docs/assets/js/25.bbf8bff1.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[25],{369:function(a,r,t){"use strict";t.r(r);var _=t(42),e=Object(_.a)({},(function(){var a=this,r=a.$createElement,t=a._self._c||r;return t("ContentSlotsDistributor",{attrs:{"slot-key":a.$parent.slotKey}},[t("h2",{attrs:{id:"概述"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#概述"}},[a._v("#")]),a._v(" 概述")]),a._v(" "),t("p",[a._v("角色管理功能维护角色元数据,通过配置角色拥有的菜单资源,限制用户只能操作拥有的角色对应的菜单资源,下面介绍角色管理功能的操作。")]),a._v(" "),t("h2",{attrs:{id:"角色列表"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#角色列表"}},[a._v("#")]),a._v(" 角色列表")]),a._v(" "),t("p",[a._v("菜单位置:权限管理 > 角色管理。点击菜单后进入角色列表页面,如图所示。")]),a._v(" "),t("p",[t("img",{attrs:{src:"/manager_role_list_query.png",alt:"manager_role_list_query"}})]),a._v(" "),t("h2",{attrs:{id:"添加角色"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#添加角色"}},[a._v("#")]),a._v(" 添加角色")]),a._v(" "),t("p",[a._v("点击 新增 按钮弹出新增窗口,如图所示。")]),a._v(" "),t("p",[t("img",{attrs:{src:"/manager_role_add_1.png",alt:"manager_role_add_1"}})]),a._v(" "),t("p",[t("img",{attrs:{src:"/manager_role_add_2.png",alt:"manager_role_add_2"}})]),a._v(" "),t("h2",{attrs:{id:"权限设置"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#权限设置"}},[a._v("#")]),a._v(" 权限设置")]),a._v(" "),t("p",[a._v("勾选需要分配权限的角色,点击 权限设置 按钮弹出角色权限配置窗口,如图所示。")]),a._v(" "),t("p",[t("img",{attrs:{src:"/manager_role_auth_1.png",alt:"manager_role_auth_1"}})]),a._v(" "),t("p",[t("img",{attrs:{src:"/manager_role_auth_2.png",alt:"manager_role_auth_2"}})]),a._v(" "),t("p",[a._v("勾选菜单后点击 确定 按钮确认给角色分配菜单权限。")]),a._v(" "),t("h2",{attrs:{id:"编辑角色"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#编辑角色"}},[a._v("#")]),a._v(" 编辑角色")]),a._v(" "),t("p",[a._v("点击 编辑 按钮弹出编辑窗口,如图所示。")]),a._v(" "),t("p",[t("img",{attrs:{src:"/manager_role_edit_1.png",alt:"manager_role_edit_1"}})]),a._v(" "),t("p",[t("img",{attrs:{src:"/manager_role_edit_2.png",alt:"manager_role_edit_2"}})]),a._v(" "),t("h2",{attrs:{id:"删除角色"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#删除角色"}},[a._v("#")]),a._v(" 删除角色")]),a._v(" "),t("p",[a._v("点击 删除 按钮弹出删除确认窗口,如图所示。")]),a._v(" "),t("p",[t("img",{attrs:{src:"/manager_role_delete_1.png",alt:"manager_role_delete_1"}})]),a._v(" "),t("p",[t("img",{attrs:{src:"/manager_role_delete_2.png",alt:"manager_role_delete_2"}})]),a._v(" "),t("p",[a._v("点击 确定 按钮后删除角色。")])])}),[],!1,null,null,null);r.default=e.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[25],{371:function(a,r,t){"use strict";t.r(r);var _=t(42),e=Object(_.a)({},(function(){var a=this,r=a.$createElement,t=a._self._c||r;return t("ContentSlotsDistributor",{attrs:{"slot-key":a.$parent.slotKey}},[t("h2",{attrs:{id:"概述"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#概述"}},[a._v("#")]),a._v(" 概述")]),a._v(" "),t("p",[a._v("角色管理功能维护角色元数据,通过配置角色拥有的菜单资源,限制用户只能操作拥有的角色对应的菜单资源,下面介绍角色管理功能的操作。")]),a._v(" "),t("h2",{attrs:{id:"角色列表"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#角色列表"}},[a._v("#")]),a._v(" 角色列表")]),a._v(" "),t("p",[a._v("菜单位置:权限管理 > 角色管理。点击菜单后进入角色列表页面,如图所示。")]),a._v(" "),t("p",[t("img",{attrs:{src:"/manager_role_list_query.png",alt:"manager_role_list_query"}})]),a._v(" "),t("h2",{attrs:{id:"添加角色"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#添加角色"}},[a._v("#")]),a._v(" 添加角色")]),a._v(" "),t("p",[a._v("点击 新增 按钮弹出新增窗口,如图所示。")]),a._v(" "),t("p",[t("img",{attrs:{src:"/manager_role_add_1.png",alt:"manager_role_add_1"}})]),a._v(" "),t("p",[t("img",{attrs:{src:"/manager_role_add_2.png",alt:"manager_role_add_2"}})]),a._v(" "),t("h2",{attrs:{id:"权限设置"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#权限设置"}},[a._v("#")]),a._v(" 权限设置")]),a._v(" "),t("p",[a._v("勾选需要分配权限的角色,点击 权限设置 按钮弹出角色权限配置窗口,如图所示。")]),a._v(" "),t("p",[t("img",{attrs:{src:"/manager_role_auth_1.png",alt:"manager_role_auth_1"}})]),a._v(" "),t("p",[t("img",{attrs:{src:"/manager_role_auth_2.png",alt:"manager_role_auth_2"}})]),a._v(" "),t("p",[a._v("勾选菜单后点击 确定 按钮确认给角色分配菜单权限。")]),a._v(" "),t("h2",{attrs:{id:"编辑角色"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#编辑角色"}},[a._v("#")]),a._v(" 编辑角色")]),a._v(" "),t("p",[a._v("点击 编辑 按钮弹出编辑窗口,如图所示。")]),a._v(" "),t("p",[t("img",{attrs:{src:"/manager_role_edit_1.png",alt:"manager_role_edit_1"}})]),a._v(" "),t("p",[t("img",{attrs:{src:"/manager_role_edit_2.png",alt:"manager_role_edit_2"}})]),a._v(" "),t("h2",{attrs:{id:"删除角色"}},[t("a",{staticClass:"header-anchor",attrs:{href:"#删除角色"}},[a._v("#")]),a._v(" 删除角色")]),a._v(" "),t("p",[a._v("点击 删除 按钮弹出删除确认窗口,如图所示。")]),a._v(" "),t("p",[t("img",{attrs:{src:"/manager_role_delete_1.png",alt:"manager_role_delete_1"}})]),a._v(" "),t("p",[t("img",{attrs:{src:"/manager_role_delete_2.png",alt:"manager_role_delete_2"}})]),a._v(" "),t("p",[a._v("点击 确定 按钮后删除角色。")])])}),[],!1,null,null,null);r.default=e.exports}}]); \ No newline at end of file diff --git a/docs/assets/js/26.b4625fe9.js b/docs/assets/js/26.70321f43.js similarity index 98% rename from docs/assets/js/26.b4625fe9.js rename to docs/assets/js/26.70321f43.js index e20ad62..f503678 100644 --- a/docs/assets/js/26.b4625fe9.js +++ b/docs/assets/js/26.70321f43.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[26],{375:function(a,e,_){"use strict";_.r(e);var r=_(42),t=Object(r.a)({},(function(){var a=this,e=a.$createElement,_=a._self._c||e;return _("ContentSlotsDistributor",{attrs:{"slot-key":a.$parent.slotKey}},[_("h2",{attrs:{id:"概述"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#概述"}},[a._v("#")]),a._v(" 概述")]),a._v(" "),_("p",[a._v("服务管理功能维护服务元数据。服务编排中的服务是一个逻辑上的概念,用于对聚合接口的归类以及权限的分配。Fizz网关聚合接口的请求路径格式为 http://{ip}:{port}/proxy/{service}{apiPath},服务对应{service}段。")]),a._v(" "),_("h2",{attrs:{id:"服务列表"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#服务列表"}},[a._v("#")]),a._v(" 服务列表")]),a._v(" "),_("p",[a._v("菜单位置:服务编排 > 服务管理。点击菜单后进入服务列表页面,如图所示。")]),a._v(" "),_("p",[_("img",{attrs:{src:"/manager_service_list_query.png",alt:"manager_service_list_query"}})]),a._v(" "),_("h2",{attrs:{id:"新增服务"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#新增服务"}},[a._v("#")]),a._v(" 新增服务")]),a._v(" "),_("p",[a._v("点击 新增 按钮弹出新增窗口,如图所示。")]),a._v(" "),_("p",[_("img",{attrs:{src:"/manager_service_add_1.png",alt:"manager_service_add_1"}})]),a._v(" "),_("p",[_("img",{attrs:{src:"/manager_service_add_2.png",alt:"manager_service_add_2"}})]),a._v(" "),_("p",[a._v("服务 ID:服务唯一标识,对应Fizz网关聚合接口请求路径(格式为 http://{ip}:{port}/proxy/{service}{apiPath})的{service}段,长度不能超过200个字符,必填;")]),a._v(" "),_("p",[a._v("服务名:服务名称,用于展示或者选项使用,必填;")]),a._v(" "),_("p",[a._v("团队:团队名称,长度不能超过200个字符;")]),a._v(" "),_("p",[a._v("负责人:负责人名称,长度不能超过200个字符;")]),a._v(" "),_("p",[a._v("描述:服务描述,长度不能超过2000个字符。")]),a._v(" "),_("h2",{attrs:{id:"编辑服务"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#编辑服务"}},[a._v("#")]),a._v(" 编辑服务")]),a._v(" "),_("p",[a._v("点击 编辑 按钮弹出编辑窗口,如图所示。")]),a._v(" "),_("p",[_("img",{attrs:{src:"/manager_service_edit_1.png",alt:"manager_service_edit_1"}})]),a._v(" "),_("p",[_("img",{attrs:{src:"/manager_service_edit_2.png",alt:"manager_service_edit_2"}})]),a._v(" "),_("h2",{attrs:{id:"删除服务"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#删除服务"}},[a._v("#")]),a._v(" 删除服务")]),a._v(" "),_("p",[a._v("点击 删除 按钮弹出删除确认窗口,如图所示。")]),a._v(" "),_("p",[_("img",{attrs:{src:"/manager_service_delete_1.png",alt:"manager_service_delete_1"}})]),a._v(" "),_("p",[_("img",{attrs:{src:"/manager_service_delete_2.png",alt:"manager_service_delete_2"}})]),a._v(" "),_("p",[a._v("点击 确定 按钮后删除服务,如果服务存在关联的聚合接口时,需要将关联的聚合接口全部删除后才能删除服务。")]),a._v(" "),_("h2",{attrs:{id:"服务权限分配"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#服务权限分配"}},[a._v("#")]),a._v(" 服务权限分配")]),a._v(" "),_("p",[a._v("点击 权限 按钮弹出权限配置窗口,如图所示。")]),a._v(" "),_("p",[_("img",{attrs:{src:"/manager_service_auth_1.png",alt:"manager_service_auth_1"}})]),a._v(" "),_("p",[_("img",{attrs:{src:"/manager_service_auth_2.png",alt:"manager_service_auth_2"}})]),a._v(" "),_("p",[a._v("服务创建人自动获得服务权限,服务权限可分配,拥有权限的用户才能操作对应的接口列表。")])])}),[],!1,null,null,null);e.default=t.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[26],{372:function(a,e,_){"use strict";_.r(e);var r=_(42),t=Object(r.a)({},(function(){var a=this,e=a.$createElement,_=a._self._c||e;return _("ContentSlotsDistributor",{attrs:{"slot-key":a.$parent.slotKey}},[_("h2",{attrs:{id:"概述"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#概述"}},[a._v("#")]),a._v(" 概述")]),a._v(" "),_("p",[a._v("服务管理功能维护服务元数据。服务编排中的服务是一个逻辑上的概念,用于对聚合接口的归类以及权限的分配。Fizz网关聚合接口的请求路径格式为 http://{ip}:{port}/proxy/{service}{apiPath},服务对应{service}段。")]),a._v(" "),_("h2",{attrs:{id:"服务列表"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#服务列表"}},[a._v("#")]),a._v(" 服务列表")]),a._v(" "),_("p",[a._v("菜单位置:服务编排 > 服务管理。点击菜单后进入服务列表页面,如图所示。")]),a._v(" "),_("p",[_("img",{attrs:{src:"/manager_service_list_query.png",alt:"manager_service_list_query"}})]),a._v(" "),_("h2",{attrs:{id:"新增服务"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#新增服务"}},[a._v("#")]),a._v(" 新增服务")]),a._v(" "),_("p",[a._v("点击 新增 按钮弹出新增窗口,如图所示。")]),a._v(" "),_("p",[_("img",{attrs:{src:"/manager_service_add_1.png",alt:"manager_service_add_1"}})]),a._v(" "),_("p",[_("img",{attrs:{src:"/manager_service_add_2.png",alt:"manager_service_add_2"}})]),a._v(" "),_("p",[a._v("服务 ID:服务唯一标识,对应Fizz网关聚合接口请求路径(格式为 http://{ip}:{port}/proxy/{service}{apiPath})的{service}段,长度不能超过200个字符,必填;")]),a._v(" "),_("p",[a._v("服务名:服务名称,用于展示或者选项使用,必填;")]),a._v(" "),_("p",[a._v("团队:团队名称,长度不能超过200个字符;")]),a._v(" "),_("p",[a._v("负责人:负责人名称,长度不能超过200个字符;")]),a._v(" "),_("p",[a._v("描述:服务描述,长度不能超过2000个字符。")]),a._v(" "),_("h2",{attrs:{id:"编辑服务"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#编辑服务"}},[a._v("#")]),a._v(" 编辑服务")]),a._v(" "),_("p",[a._v("点击 编辑 按钮弹出编辑窗口,如图所示。")]),a._v(" "),_("p",[_("img",{attrs:{src:"/manager_service_edit_1.png",alt:"manager_service_edit_1"}})]),a._v(" "),_("p",[_("img",{attrs:{src:"/manager_service_edit_2.png",alt:"manager_service_edit_2"}})]),a._v(" "),_("h2",{attrs:{id:"删除服务"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#删除服务"}},[a._v("#")]),a._v(" 删除服务")]),a._v(" "),_("p",[a._v("点击 删除 按钮弹出删除确认窗口,如图所示。")]),a._v(" "),_("p",[_("img",{attrs:{src:"/manager_service_delete_1.png",alt:"manager_service_delete_1"}})]),a._v(" "),_("p",[_("img",{attrs:{src:"/manager_service_delete_2.png",alt:"manager_service_delete_2"}})]),a._v(" "),_("p",[a._v("点击 确定 按钮后删除服务,如果服务存在关联的聚合接口时,需要将关联的聚合接口全部删除后才能删除服务。")]),a._v(" "),_("h2",{attrs:{id:"服务权限分配"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#服务权限分配"}},[a._v("#")]),a._v(" 服务权限分配")]),a._v(" "),_("p",[a._v("点击 权限 按钮弹出权限配置窗口,如图所示。")]),a._v(" "),_("p",[_("img",{attrs:{src:"/manager_service_auth_1.png",alt:"manager_service_auth_1"}})]),a._v(" "),_("p",[_("img",{attrs:{src:"/manager_service_auth_2.png",alt:"manager_service_auth_2"}})]),a._v(" "),_("p",[a._v("服务创建人自动获得服务权限,服务权限可分配,拥有权限的用户才能操作对应的接口列表。")])])}),[],!1,null,null,null);e.default=t.exports}}]); \ No newline at end of file diff --git a/docs/assets/js/27.20a7e33d.js b/docs/assets/js/27.505a813e.js similarity index 97% rename from docs/assets/js/27.20a7e33d.js rename to docs/assets/js/27.505a813e.js index 8861c16..2af9848 100644 --- a/docs/assets/js/27.20a7e33d.js +++ b/docs/assets/js/27.505a813e.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[27],{374:function(t,a,s){"use strict";s.r(a);var _=s(42),r=Object(_.a)({},(function(){var t=this,a=t.$createElement,s=t._self._c||a;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("h2",{attrs:{id:"概述"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#概述"}},[t._v("#")]),t._v(" 概述")]),t._v(" "),s("p",[t._v("Fizz网关会将访问请求数据(IP地址、网关分组、服务、应用、请求方法、API Path、请求时间)推送到Kafka中,管理后台消费Kafka消息统计接口访问数据。")]),t._v(" "),s("p",[t._v("接口统计功能以图表的形式展示指定时间段内每日的接口总数、访问次数,可查看接口的历史访问总次数以及最近请求时间。")]),t._v(" "),s("h2",{attrs:{id:"接口访问统计"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#接口访问统计"}},[t._v("#")]),t._v(" 接口访问统计")]),t._v(" "),s("p",[t._v("菜单位置:网关管理 > 接口统计。点击菜单后进入接口统计页面,如图所示。")]),t._v(" "),s("p",[s("img",{attrs:{src:"/manager_source_statistics_1.png",alt:"manager_source_statistics_1.png"}})]),t._v(" "),s("p",[t._v("今天接口总数:从0时到当前时刻被调用不同接口的总数;")]),t._v(" "),s("p",[t._v("今天访问次数:从0时到当前时刻访问请求的总次数。")]),t._v(" "),s("p",[t._v("接口总数图表:显示指定时间段内每日被调用不同接口的总数曲线;")]),t._v(" "),s("p",[t._v("访问次数图表:显示指定时间段内每日访问请求的总次数曲线。")]),t._v(" "),s("h2",{attrs:{id:"请求统计"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#请求统计"}},[t._v("#")]),t._v(" 请求统计")]),t._v(" "),s("p",[t._v("接口统计界面下部为请求统计列表,如图所示。")]),t._v(" "),s("p",[s("img",{attrs:{src:"/manager_source_statistics_2.png",alt:"manager_source_statistics_2.png"}})]),t._v(" "),s("p",[t._v("来源IP:网关请求的实际入口IP地址;")]),t._v(" "),s("p",[t._v("请求次数:( 唯一[来源IP、网关分组、服务名、请求方法、appID、API Path])历史总请求次数;")]),t._v(" "),s("p",[t._v("最近请求时间:( 唯一[来源IP、网关分组、服务名、请求方法、appID、API Path])最近一次调用时间。")])])}),[],!1,null,null,null);a.default=r.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[27],{373:function(t,a,s){"use strict";s.r(a);var _=s(42),r=Object(_.a)({},(function(){var t=this,a=t.$createElement,s=t._self._c||a;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("h2",{attrs:{id:"概述"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#概述"}},[t._v("#")]),t._v(" 概述")]),t._v(" "),s("p",[t._v("Fizz网关会将访问请求数据(IP地址、网关分组、服务、应用、请求方法、API Path、请求时间)推送到Kafka中,管理后台消费Kafka消息统计接口访问数据。")]),t._v(" "),s("p",[t._v("接口统计功能以图表的形式展示指定时间段内每日的接口总数、访问次数,可查看接口的历史访问总次数以及最近请求时间。")]),t._v(" "),s("h2",{attrs:{id:"接口访问统计"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#接口访问统计"}},[t._v("#")]),t._v(" 接口访问统计")]),t._v(" "),s("p",[t._v("菜单位置:网关管理 > 接口统计。点击菜单后进入接口统计页面,如图所示。")]),t._v(" "),s("p",[s("img",{attrs:{src:"/manager_source_statistics_1.png",alt:"manager_source_statistics_1.png"}})]),t._v(" "),s("p",[t._v("今天接口总数:从0时到当前时刻被调用不同接口的总数;")]),t._v(" "),s("p",[t._v("今天访问次数:从0时到当前时刻访问请求的总次数。")]),t._v(" "),s("p",[t._v("接口总数图表:显示指定时间段内每日被调用不同接口的总数曲线;")]),t._v(" "),s("p",[t._v("访问次数图表:显示指定时间段内每日访问请求的总次数曲线。")]),t._v(" "),s("h2",{attrs:{id:"请求统计"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#请求统计"}},[t._v("#")]),t._v(" 请求统计")]),t._v(" "),s("p",[t._v("接口统计界面下部为请求统计列表,如图所示。")]),t._v(" "),s("p",[s("img",{attrs:{src:"/manager_source_statistics_2.png",alt:"manager_source_statistics_2.png"}})]),t._v(" "),s("p",[t._v("来源IP:网关请求的实际入口IP地址;")]),t._v(" "),s("p",[t._v("请求次数:( 唯一[来源IP、网关分组、服务名、请求方法、appID、API Path])历史总请求次数;")]),t._v(" "),s("p",[t._v("最近请求时间:( 唯一[来源IP、网关分组、服务名、请求方法、appID、API Path])最近一次调用时间。")])])}),[],!1,null,null,null);a.default=r.exports}}]); \ No newline at end of file diff --git a/docs/assets/js/28.3d35b618.js b/docs/assets/js/28.2160d3a0.js similarity index 97% rename from docs/assets/js/28.3d35b618.js rename to docs/assets/js/28.2160d3a0.js index e0b5dbb..c49449b 100644 --- a/docs/assets/js/28.3d35b618.js +++ b/docs/assets/js/28.2160d3a0.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[28],{371:function(a,r,_){"use strict";_.r(r);var t=_(42),e=Object(t.a)({},(function(){var a=this,r=a.$createElement,_=a._self._c||r;return _("ContentSlotsDistributor",{attrs:{"slot-key":a.$parent.slotKey}},[_("h2",{attrs:{id:"概述"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#概述"}},[a._v("#")]),a._v(" 概述")]),a._v(" "),_("p",[a._v("用户管理功能用于维护用户元数据,包括用户信息维护、密码维护、角色配置。")]),a._v(" "),_("h2",{attrs:{id:"用户列表"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#用户列表"}},[a._v("#")]),a._v(" 用户列表")]),a._v(" "),_("p",[a._v("菜单位置:系统管理 > 用户管理。点击菜单后进入用户列表页面,如图所示。")]),a._v(" "),_("p",[_("img",{attrs:{src:"/manager_user_list_query.png",alt:"manager_user_list_query"}})]),a._v(" "),_("h2",{attrs:{id:"添加用户"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#添加用户"}},[a._v("#")]),a._v(" 添加用户")]),a._v(" "),_("p",[a._v("点击 新增 按钮弹出新增窗口,如图所示。")]),a._v(" "),_("p",[_("img",{attrs:{src:"/manager_user_add_1.png",alt:"manager_user_add_1"}})]),a._v(" "),_("p",[_("img",{attrs:{src:"/manager_user_add_2.png",alt:"manager_user_add_2"}})]),a._v(" "),_("p",[a._v("电子邮箱:用户用于接收电子邮件的邮箱地址,后台涉及邮件发送业务使用该字段设置的邮箱地址来进行邮箱发送。")]),a._v(" "),_("h2",{attrs:{id:"重置密码"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#重置密码"}},[a._v("#")]),a._v(" 重置密码")]),a._v(" "),_("p",[a._v("勾选用户后点击 密码重置 按钮可为用户重置密码。")]),a._v(" "),_("p",[_("img",{attrs:{src:"/manager_user_reset_password_1.png",alt:"manager_user_reset_password_1"}})]),a._v(" "),_("p",[_("img",{attrs:{src:"/manager_user_reset_password_2.png",alt:"manager_user_reset_password_2"}})]),a._v(" "),_("p",[a._v("重置后的默认密码为"),_("code",[a._v("AsdF1234!")]),a._v("。")]),a._v(" "),_("h2",{attrs:{id:"编辑用户"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#编辑用户"}},[a._v("#")]),a._v(" 编辑用户")]),a._v(" "),_("p",[a._v("点击 编辑 按钮弹出编辑窗口,如图所示。")]),a._v(" "),_("p",[_("img",{attrs:{src:"/manager_user_edit_1.png",alt:"manager_user_edit_1"}})]),a._v(" "),_("p",[_("img",{attrs:{src:"/manager_user_edit_2.png",alt:"manager_user_edit_2"}})]),a._v(" "),_("h2",{attrs:{id:"删除用户"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#删除用户"}},[a._v("#")]),a._v(" 删除用户")]),a._v(" "),_("p",[a._v("点击 删除 按钮弹出删除确认窗口,如图所示。")]),a._v(" "),_("p",[_("img",{attrs:{src:"/manager_user_delete_1.png",alt:"manager_user_delete_1"}})]),a._v(" "),_("p",[_("img",{attrs:{src:"/manager_user_delete_2.png",alt:"manager_user_delete_2"}})])])}),[],!1,null,null,null);r.default=e.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[28],{375:function(a,r,_){"use strict";_.r(r);var t=_(42),e=Object(t.a)({},(function(){var a=this,r=a.$createElement,_=a._self._c||r;return _("ContentSlotsDistributor",{attrs:{"slot-key":a.$parent.slotKey}},[_("h2",{attrs:{id:"概述"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#概述"}},[a._v("#")]),a._v(" 概述")]),a._v(" "),_("p",[a._v("用户管理功能用于维护用户元数据,包括用户信息维护、密码维护、角色配置。")]),a._v(" "),_("h2",{attrs:{id:"用户列表"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#用户列表"}},[a._v("#")]),a._v(" 用户列表")]),a._v(" "),_("p",[a._v("菜单位置:系统管理 > 用户管理。点击菜单后进入用户列表页面,如图所示。")]),a._v(" "),_("p",[_("img",{attrs:{src:"/manager_user_list_query.png",alt:"manager_user_list_query"}})]),a._v(" "),_("h2",{attrs:{id:"添加用户"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#添加用户"}},[a._v("#")]),a._v(" 添加用户")]),a._v(" "),_("p",[a._v("点击 新增 按钮弹出新增窗口,如图所示。")]),a._v(" "),_("p",[_("img",{attrs:{src:"/manager_user_add_1.png",alt:"manager_user_add_1"}})]),a._v(" "),_("p",[_("img",{attrs:{src:"/manager_user_add_2.png",alt:"manager_user_add_2"}})]),a._v(" "),_("p",[a._v("电子邮箱:用户用于接收电子邮件的邮箱地址,后台涉及邮件发送业务使用该字段设置的邮箱地址来进行邮箱发送。")]),a._v(" "),_("h2",{attrs:{id:"重置密码"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#重置密码"}},[a._v("#")]),a._v(" 重置密码")]),a._v(" "),_("p",[a._v("勾选用户后点击 密码重置 按钮可为用户重置密码。")]),a._v(" "),_("p",[_("img",{attrs:{src:"/manager_user_reset_password_1.png",alt:"manager_user_reset_password_1"}})]),a._v(" "),_("p",[_("img",{attrs:{src:"/manager_user_reset_password_2.png",alt:"manager_user_reset_password_2"}})]),a._v(" "),_("p",[a._v("重置后的默认密码为"),_("code",[a._v("AsdF1234!")]),a._v("。")]),a._v(" "),_("h2",{attrs:{id:"编辑用户"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#编辑用户"}},[a._v("#")]),a._v(" 编辑用户")]),a._v(" "),_("p",[a._v("点击 编辑 按钮弹出编辑窗口,如图所示。")]),a._v(" "),_("p",[_("img",{attrs:{src:"/manager_user_edit_1.png",alt:"manager_user_edit_1"}})]),a._v(" "),_("p",[_("img",{attrs:{src:"/manager_user_edit_2.png",alt:"manager_user_edit_2"}})]),a._v(" "),_("h2",{attrs:{id:"删除用户"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#删除用户"}},[a._v("#")]),a._v(" 删除用户")]),a._v(" "),_("p",[a._v("点击 删除 按钮弹出删除确认窗口,如图所示。")]),a._v(" "),_("p",[_("img",{attrs:{src:"/manager_user_delete_1.png",alt:"manager_user_delete_1"}})]),a._v(" "),_("p",[_("img",{attrs:{src:"/manager_user_delete_2.png",alt:"manager_user_delete_2"}})])])}),[],!1,null,null,null);r.default=e.exports}}]); \ No newline at end of file diff --git a/docs/assets/js/29.60b7285b.js b/docs/assets/js/29.ab810898.js similarity index 99% rename from docs/assets/js/29.60b7285b.js rename to docs/assets/js/29.ab810898.js index 931d607..3d4bbe5 100644 --- a/docs/assets/js/29.60b7285b.js +++ b/docs/assets/js/29.ab810898.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[29],{376:function(t,s,a){"use strict";a.r(s);var n=a(42),e=Object(n.a)({},(function(){var t=this,s=t.$createElement,a=t._self._c||s;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("h2",{attrs:{id:"概述"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#概述"}},[t._v("#")]),t._v(" 概述")]),t._v(" "),a("p",[t._v("当需要在gateway中加入自定义的逻辑时,可通过fizz的插件机制实现,插件:"),a("br"),t._v("\n1、类似spring的WebFilter,是fizz内部的WebFilter,由fizz调度;"),a("br"),t._v("\n2、对不同的请求,可配置不同的上下文参数,可通过manager完成配置;"),a("br"),t._v("\n3、若有多个插件,当前插件可获取前面插件的执行结果。")]),t._v(" "),a("p",[t._v("插件的开发和应用,分gateway开发、manager配置两部分,下面以一个例子,依次介绍。")]),t._v(" "),a("h2",{attrs:{id:"gateway开发"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#gateway开发"}},[t._v("#")]),t._v(" gateway开发")]),t._v(" "),a("div",{staticClass:"language-java extra-class"},[a("pre",{pre:!0,attrs:{class:"language-java"}},[a("code",[t._v(" 实现\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("abstract")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("PluginFilter")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("abstract")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Mono")]),a("span",{pre:!0,attrs:{class:"token generics"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Void")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("doFilter")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ServerWebExchange")]),t._v(" exchange"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Map")]),a("span",{pre:!0,attrs:{class:"token generics"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("String")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Object")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v(" config"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("String")]),t._v(" fixedConfig"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n 即定义了一个插件。\n \n 比如\n "),a("span",{pre:!0,attrs:{class:"token annotation punctuation"}},[t._v("@Component")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("TestPluginFilter")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("TEST_PLUGIN_FILTER"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("TestPluginFilter")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("extends")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("PluginFilter")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n \n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("private")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("static")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("final")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Logger")]),t._v(" log "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("LoggerFactory")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("getLogger")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("TestPluginFilter")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n \n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("static")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("final")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("String")]),t._v(" TEST_PLUGIN_FILTER "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"testPlugin"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n \n "),a("span",{pre:!0,attrs:{class:"token annotation punctuation"}},[t._v("@Override")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Mono")]),a("span",{pre:!0,attrs:{class:"token generics"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Void")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("doFilter")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ServerWebExchange")]),t._v(" exchange"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Map")]),a("span",{pre:!0,attrs:{class:"token generics"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("String")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Object")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v(" config"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("String")]),t._v(" fixedConfig"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("String")]),t._v(" rid "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" exchange"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("getRequest")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("getId")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Boolean")]),t._v(" logReqId "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Boolean")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" config"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("get")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"logReqId"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 是否记录请求id日志,可通过manager配置")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("logReqId "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("null")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" logReqId"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n log"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("info")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("exchange"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("getRequest")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("getURI")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("toString")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('" 的请求id: "')]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" rid"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Boolean")]),t._v(" appendFizzRsv "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Boolean")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" config"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("get")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"appendFizzRsv"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("appendFizzRsv "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("null")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" appendFizzRsv"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("WebUtils")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("appendHeader")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("exchange"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"FIZZ-RSV"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" rid"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("WebUtils")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("transmitSuccessFilterResultAndEmptyMono")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("exchange"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" TEST_PLUGIN_FILTER"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("null")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 保存插件执行结果,并返回")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n 这个插件,插件必须是一个spring的"),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Component")]),t._v("(或子注解),且要有id,这个插件的id是testPlugin,它实现了两个功能,记录请求id日志,转发请求时添加FIZZ"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("-")]),t._v("RSV请求头,并且功能是可打开或关闭的。\n \n 另外可通过:\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("WebUtils")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("getPrevFilterResult")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("exchange"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" 获取上一个插件的执行结果,\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("WebUtils")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("getFilterResult")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("exchange"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"plugin.id"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" 获取已执行的任意一个插件的执行结果。\n")])])]),a("h2",{attrs:{id:"manager配置"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#manager配置"}},[t._v("#")]),t._v(" manager配置")]),t._v(" "),a("p",[t._v("1、定义插件")]),t._v(" "),a("div",{staticClass:"language-sql extra-class"},[a("pre",{pre:!0,attrs:{class:"language-sql"}},[a("code",[t._v(" 在插件表中,定义上面的插件: \n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("INSERT")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("INTO")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("`")]),t._v("tb_plugin"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("`")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("`")]),t._v("eng_name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("`")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("`")]),t._v("chn_name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("`")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("`")]),t._v("config"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("`")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("`")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("order")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("`")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" \n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("VALUES")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'testPlugin'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'测试插件'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('\'[{\\"field\\":\\"logReqId\\",\\"label\\":\\"打印请求id日志\\",\\"component\\":\\"radio\\",\\"dataType\\":\\"boolean\\",\\"default\\":false,\\"options\\":[{\\"label\\":\\"是\\",\\"value\\":true},{\\"label\\":\\"否\\",\\"value\\":false}]},{\\"field\\":\\"appendFizzRsv\\",\\"label\\":\\"添加fizzRsv请求头\\",\\"component\\":\\"radio\\",\\"dataType\\":\\"boolean\\",\\"default\\":false,\\"options\\":[{\\"label\\":\\"是\\",\\"value\\":true},{\\"label\\":\\"否\\",\\"value\\":false}]}]\'')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("250")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),a("div",{staticClass:"language-json extra-class"},[a("pre",{pre:!0,attrs:{class:"language-json"}},[a("code",[t._v(" eng_name为插件的id,chn_name为插件中文名,order为插件的执行顺序,也是插件在界面上的显示顺序。\n \n config:\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token property"}},[t._v('"field"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"logReqId"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token property"}},[t._v('"label"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"打印请求id日志"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token property"}},[t._v('"component"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"radio"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token property"}},[t._v('"dataType"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"boolean"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token property"}},[t._v('"default"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("false")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token property"}},[t._v('"options"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token property"}},[t._v('"label"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"是"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token property"}},[t._v('"value"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("true")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token property"}},[t._v('"label"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"否"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token property"}},[t._v('"value"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("false")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token property"}},[t._v('"field"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"appendFizzRsv"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token property"}},[t._v('"label"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"添加fizzRsv请求头"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token property"}},[t._v('"component"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"radio"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token property"}},[t._v('"dataType"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"boolean"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token property"}},[t._v('"default"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("false")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token property"}},[t._v('"options"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token property"}},[t._v('"label"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"是"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token property"}},[t._v('"value"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("true")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token property"}},[t._v('"label"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"否"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token property"}},[t._v('"value"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("false")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n 前端据此生成插件的配置表单,具体参前端说明。\n")])])]),a("p",[t._v("2、应用插件")]),t._v(" "),a("p",[t._v("如对\n"),a("img",{attrs:{src:"/xapi.png",alt:""}})]),t._v(" "),a("p",[t._v("接口应用插件:\n"),a("img",{attrs:{src:"/test-plugin.png",alt:""}})]),t._v(" "),a("p",[t._v('上面配置的"打印请求id日志"、"添加fizzRsv请求头",对应')]),t._v(" "),a("div",{staticClass:"language-java extra-class"},[a("pre",{pre:!0,attrs:{class:"language-java"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Mono")]),a("span",{pre:!0,attrs:{class:"token generics"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Void")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("doFilter")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ServerWebExchange")]),t._v(" exchange"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Map")]),a("span",{pre:!0,attrs:{class:"token generics"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("String")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Object")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v(" config"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("String")]),t._v(" fixedConfig"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" \n")])])]),a("p",[t._v("中config的logReqId和appendFizzRsv key。")])])}),[],!1,null,null,null);s.default=e.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[29],{377:function(t,s,a){"use strict";a.r(s);var n=a(42),e=Object(n.a)({},(function(){var t=this,s=t.$createElement,a=t._self._c||s;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("h2",{attrs:{id:"概述"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#概述"}},[t._v("#")]),t._v(" 概述")]),t._v(" "),a("p",[t._v("当需要在gateway中加入自定义的逻辑时,可通过fizz的插件机制实现,插件:"),a("br"),t._v("\n1、类似spring的WebFilter,是fizz内部的WebFilter,由fizz调度;"),a("br"),t._v("\n2、对不同的请求,可配置不同的上下文参数,可通过manager完成配置;"),a("br"),t._v("\n3、若有多个插件,当前插件可获取前面插件的执行结果。")]),t._v(" "),a("p",[t._v("插件的开发和应用,分gateway开发、manager配置两部分,下面以一个例子,依次介绍。")]),t._v(" "),a("h2",{attrs:{id:"gateway开发"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#gateway开发"}},[t._v("#")]),t._v(" gateway开发")]),t._v(" "),a("div",{staticClass:"language-java extra-class"},[a("pre",{pre:!0,attrs:{class:"language-java"}},[a("code",[t._v(" 实现\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("abstract")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("PluginFilter")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("abstract")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Mono")]),a("span",{pre:!0,attrs:{class:"token generics"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Void")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("doFilter")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ServerWebExchange")]),t._v(" exchange"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Map")]),a("span",{pre:!0,attrs:{class:"token generics"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("String")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Object")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v(" config"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("String")]),t._v(" fixedConfig"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n 即定义了一个插件。\n \n 比如\n "),a("span",{pre:!0,attrs:{class:"token annotation punctuation"}},[t._v("@Component")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("TestPluginFilter")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),t._v("TEST_PLUGIN_FILTER"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("TestPluginFilter")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("extends")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("PluginFilter")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n \n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("private")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("static")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("final")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Logger")]),t._v(" log "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("LoggerFactory")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("getLogger")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("TestPluginFilter")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("class")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n \n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("static")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("final")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("String")]),t._v(" TEST_PLUGIN_FILTER "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"testPlugin"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n \n "),a("span",{pre:!0,attrs:{class:"token annotation punctuation"}},[t._v("@Override")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Mono")]),a("span",{pre:!0,attrs:{class:"token generics"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Void")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("doFilter")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ServerWebExchange")]),t._v(" exchange"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Map")]),a("span",{pre:!0,attrs:{class:"token generics"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("String")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Object")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v(" config"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("String")]),t._v(" fixedConfig"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("String")]),t._v(" rid "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" exchange"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("getRequest")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("getId")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Boolean")]),t._v(" logReqId "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Boolean")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" config"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("get")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"logReqId"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 是否记录请求id日志,可通过manager配置")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("logReqId "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("null")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" logReqId"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n log"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("info")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("exchange"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("getRequest")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("getURI")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("toString")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('" 的请求id: "')]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("+")]),t._v(" rid"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Boolean")]),t._v(" appendFizzRsv "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Boolean")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" config"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("get")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"appendFizzRsv"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("appendFizzRsv "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("==")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("null")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" appendFizzRsv"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("WebUtils")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("appendHeader")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("exchange"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"FIZZ-RSV"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" rid"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("WebUtils")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("transmitSuccessFilterResultAndEmptyMono")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("exchange"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" TEST_PLUGIN_FILTER"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("null")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 保存插件执行结果,并返回")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n 这个插件,插件必须是一个spring的"),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Component")]),t._v("(或子注解),且要有id,这个插件的id是testPlugin,它实现了两个功能,记录请求id日志,转发请求时添加FIZZ"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("-")]),t._v("RSV请求头,并且功能是可打开或关闭的。\n \n 另外可通过:\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("WebUtils")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("getPrevFilterResult")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("exchange"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" 获取上一个插件的执行结果,\n "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("WebUtils")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("getFilterResult")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("exchange"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"plugin.id"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v(" 获取已执行的任意一个插件的执行结果。\n")])])]),a("h2",{attrs:{id:"manager配置"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#manager配置"}},[t._v("#")]),t._v(" manager配置")]),t._v(" "),a("p",[t._v("1、定义插件")]),t._v(" "),a("div",{staticClass:"language-sql extra-class"},[a("pre",{pre:!0,attrs:{class:"language-sql"}},[a("code",[t._v(" 在插件表中,定义上面的插件: \n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("INSERT")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("INTO")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("`")]),t._v("tb_plugin"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("`")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("`")]),t._v("eng_name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("`")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("`")]),t._v("chn_name"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("`")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("`")]),t._v("config"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("`")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("`")]),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("order")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("`")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" \n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("VALUES")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'testPlugin'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'测试插件'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('\'[{\\"field\\":\\"logReqId\\",\\"label\\":\\"打印请求id日志\\",\\"component\\":\\"radio\\",\\"dataType\\":\\"boolean\\",\\"default\\":false,\\"options\\":[{\\"label\\":\\"是\\",\\"value\\":true},{\\"label\\":\\"否\\",\\"value\\":false}]},{\\"field\\":\\"appendFizzRsv\\",\\"label\\":\\"添加fizzRsv请求头\\",\\"component\\":\\"radio\\",\\"dataType\\":\\"boolean\\",\\"default\\":false,\\"options\\":[{\\"label\\":\\"是\\",\\"value\\":true},{\\"label\\":\\"否\\",\\"value\\":false}]}]\'')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("250")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n")])])]),a("div",{staticClass:"language-json extra-class"},[a("pre",{pre:!0,attrs:{class:"language-json"}},[a("code",[t._v(" eng_name为插件的id,chn_name为插件中文名,order为插件的执行顺序,也是插件在界面上的显示顺序。\n \n config:\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token property"}},[t._v('"field"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"logReqId"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token property"}},[t._v('"label"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"打印请求id日志"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token property"}},[t._v('"component"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"radio"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token property"}},[t._v('"dataType"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"boolean"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token property"}},[t._v('"default"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("false")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token property"}},[t._v('"options"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token property"}},[t._v('"label"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"是"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token property"}},[t._v('"value"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("true")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token property"}},[t._v('"label"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"否"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token property"}},[t._v('"value"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("false")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token property"}},[t._v('"field"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"appendFizzRsv"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token property"}},[t._v('"label"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"添加fizzRsv请求头"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token property"}},[t._v('"component"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"radio"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token property"}},[t._v('"dataType"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"boolean"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token property"}},[t._v('"default"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("false")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token property"}},[t._v('"options"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token property"}},[t._v('"label"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"是"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token property"}},[t._v('"value"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("true")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token property"}},[t._v('"label"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"否"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token property"}},[t._v('"value"')]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("false")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n 前端据此生成插件的配置表单,具体参前端说明。\n")])])]),a("p",[t._v("2、应用插件")]),t._v(" "),a("p",[t._v("如对\n"),a("img",{attrs:{src:"/xapi.png",alt:""}})]),t._v(" "),a("p",[t._v("接口应用插件:\n"),a("img",{attrs:{src:"/test-plugin.png",alt:""}})]),t._v(" "),a("p",[t._v('上面配置的"打印请求id日志"、"添加fizzRsv请求头",对应')]),t._v(" "),a("div",{staticClass:"language-java extra-class"},[a("pre",{pre:!0,attrs:{class:"language-java"}},[a("code",[a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("public")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Mono")]),a("span",{pre:!0,attrs:{class:"token generics"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Void")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v(" "),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("doFilter")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("ServerWebExchange")]),t._v(" exchange"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Map")]),a("span",{pre:!0,attrs:{class:"token generics"}},[a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("<")]),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("String")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("Object")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(">")])]),t._v(" config"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token class-name"}},[t._v("String")]),t._v(" fixedConfig"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" \n")])])]),a("p",[t._v("中config的logReqId和appendFizzRsv key。")])])}),[],!1,null,null,null);s.default=e.exports}}]); \ No newline at end of file diff --git a/docs/assets/js/3.a51774e3.js b/docs/assets/js/3.13d0117a.js similarity index 87% rename from docs/assets/js/3.a51774e3.js rename to docs/assets/js/3.13d0117a.js index 231bae9..cfebf44 100644 --- a/docs/assets/js/3.a51774e3.js +++ b/docs/assets/js/3.13d0117a.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[3],{317:function(t,e,n){},348:function(t,e,n){"use strict";var i=n(317);n.n(i).a},377:function(t,e,n){"use strict";n.r(e);var i={functional:!0,props:{type:{type:String,default:"tip"},text:String,vertical:{type:String,default:"top"}},render:function(t,e){var n=e.props,i=e.slots;return t("span",{class:["badge",n.type],style:{verticalAlign:n.vertical}},n.text||i().default)}},r=(n(348),n(42)),a=Object(r.a)(i,void 0,void 0,!1,null,"15b7b770",null);e.default=a.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[3],{317:function(t,e,n){},348:function(t,e,n){"use strict";var i=n(317);n.n(i).a},378:function(t,e,n){"use strict";n.r(e);var i={functional:!0,props:{type:{type:String,default:"tip"},text:String,vertical:{type:String,default:"top"}},render:function(t,e){var n=e.props,i=e.slots;return t("span",{class:["badge",n.type],style:{verticalAlign:n.vertical}},n.text||i().default)}},r=(n(348),n(42)),a=Object(r.a)(i,void 0,void 0,!1,null,"15b7b770",null);e.default=a.exports}}]); \ No newline at end of file diff --git a/docs/assets/js/30.7591e88a.js b/docs/assets/js/30.37a581ce.js similarity index 95% rename from docs/assets/js/30.7591e88a.js rename to docs/assets/js/30.37a581ce.js index 98c7472..5a485a1 100644 --- a/docs/assets/js/30.7591e88a.js +++ b/docs/assets/js/30.37a581ce.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[30],{373:function(t,e,s){"use strict";s.r(e);var a=s(42),r=Object(a.a)({},(function(){var t=this,e=t.$createElement,s=t._self._c||e;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("h2",{attrs:{id:"路由转发介绍"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#路由转发介绍"}},[t._v("#")]),t._v(" 路由转发介绍")]),t._v(" "),s("p",[t._v("路由转发也叫反向代理,为内部微服务提供统一的对外入口。支持以下功能:")]),t._v(" "),s("ul",[s("li",[t._v("支持服务注册与发现")]),t._v(" "),s("li",[t._v("支持负载均衡")]),t._v(" "),s("li",[t._v("支持黑白名单机制")]),t._v(" "),s("li",[t._v("支持配置插件")])]),t._v(" "),s("h2",{attrs:{id:"接入路由转发"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#接入路由转发"}},[t._v("#")]),t._v(" 接入路由转发")]),t._v(" "),s("ul",[s("li",[t._v("前提条件:接入Eureka注册中心")]),t._v(" "),s("li",[t._v("开通白名单,接入注册中心的服务默认不对公网开放 (白名单在配置文件里配置serviceWhiteList)")]),t._v(" "),s("li",[t._v("配置访问权限 (管理后台-接口代理-API查询)")])])])}),[],!1,null,null,null);e.default=r.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[30],{376:function(t,e,s){"use strict";s.r(e);var a=s(42),r=Object(a.a)({},(function(){var t=this,e=t.$createElement,s=t._self._c||e;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("h2",{attrs:{id:"路由转发介绍"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#路由转发介绍"}},[t._v("#")]),t._v(" 路由转发介绍")]),t._v(" "),s("p",[t._v("路由转发也叫反向代理,为内部微服务提供统一的对外入口。支持以下功能:")]),t._v(" "),s("ul",[s("li",[t._v("支持服务注册与发现")]),t._v(" "),s("li",[t._v("支持负载均衡")]),t._v(" "),s("li",[t._v("支持黑白名单机制")]),t._v(" "),s("li",[t._v("支持配置插件")])]),t._v(" "),s("h2",{attrs:{id:"接入路由转发"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#接入路由转发"}},[t._v("#")]),t._v(" 接入路由转发")]),t._v(" "),s("ul",[s("li",[t._v("前提条件:接入Eureka注册中心")]),t._v(" "),s("li",[t._v("开通白名单,接入注册中心的服务默认不对公网开放 (白名单在配置文件里配置serviceWhiteList)")]),t._v(" "),s("li",[t._v("配置访问权限 (管理后台-接口代理-API查询)")])])])}),[],!1,null,null,null);e.default=r.exports}}]); \ No newline at end of file diff --git a/docs/assets/js/31.35595b86.js b/docs/assets/js/31.35595b86.js new file mode 100644 index 0000000..06e044a --- /dev/null +++ b/docs/assets/js/31.35595b86.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[31],{374:function(v,t,_){"use strict";_.r(t);var a=_(42),s=Object(a.a)({},(function(){var v=this,t=v.$createElement,_=v._self._c||t;return _("ContentSlotsDistributor",{attrs:{"slot-key":v.$parent.slotKey}},[_("h2",{attrs:{id:"v1-2-x"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#v1-2-x"}},[v._v("#")]),v._v(" v1.2.x")]),v._v(" "),_("ul",[_("li",[v._v("支持Nacos注册中心和配置中心")]),v._v(" "),_("li",[v._v("输出服务编排脚本异常信息")]),v._v(" "),_("li",[v._v("支持在服务编排里配置重定向")]),v._v(" "),_("li",[v._v("增加内置的默认common.js")]),v._v(" "),_("li",[v._v("支持接口统计")])]),v._v(" "),_("h2",{attrs:{id:"v1-3-x"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#v1-3-x"}},[v._v("#")]),v._v(" v1.3.x")]),v._v(" "),_("ul",[_("li",[v._v("支持接口回调")]),v._v(" "),_("li",[v._v("优先路由配置")]),v._v(" "),_("li",[v._v("支持后台查看日志")]),v._v(" "),_("li",[v._v("优化单机部署")])]),v._v(" "),_("h2",{attrs:{id:"v1-4-x"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#v1-4-x"}},[v._v("#")]),v._v(" v1.4.x")]),v._v(" "),_("ul",[_("li",[v._v("支持流控管理(限流,降级,流速等)")]),v._v(" "),_("li",[v._v("支持内容模块插件化")]),v._v(" "),_("li",[v._v("支持动态添加插件")]),v._v(" "),_("li",[v._v("支持使用正则匹配路由")])]),v._v(" "),_("h2",{attrs:{id:"v1-5-x"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#v1-5-x"}},[v._v("#")]),v._v(" v1.5.x")]),v._v(" "),_("ul",[_("li",[v._v("支持Docker容器部署")]),v._v(" "),_("li",[v._v("支持MySQL input")]),v._v(" "),_("li",[v._v("发布审核功能使用工作流")])]),v._v(" "),_("h2",{attrs:{id:"v1-6-x"}},[_("a",{staticClass:"header-anchor",attrs:{href:"#v1-6-x"}},[v._v("#")]),v._v(" v1.6.x")]),v._v(" "),_("ul",[_("li",[v._v("支持Dubbo")])])])}),[],!1,null,null,null);t.default=s.exports}}]); \ No newline at end of file diff --git a/docs/assets/js/5.abc10683.js b/docs/assets/js/5.a59b20e1.js similarity index 79% rename from docs/assets/js/5.abc10683.js rename to docs/assets/js/5.a59b20e1.js index 71e393b..010a729 100644 --- a/docs/assets/js/5.abc10683.js +++ b/docs/assets/js/5.a59b20e1.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[5],{351:function(t,e,n){"use strict";n.r(e);var s=n(42),l=Object(s.a)({},(function(){var t=this.$createElement;return(this._self._c||t)("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}})}),[],!1,null,null,null);e.default=l.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[5],{352:function(t,e,n){"use strict";n.r(e);var s=n(42),l=Object(s.a)({},(function(){var t=this.$createElement;return(this._self._c||t)("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}})}),[],!1,null,null,null);e.default=l.exports}}]); \ No newline at end of file diff --git a/docs/assets/js/6.e883523c.js b/docs/assets/js/6.b5dc0bcc.js similarity index 79% rename from docs/assets/js/6.e883523c.js rename to docs/assets/js/6.b5dc0bcc.js index b633ff3..f6f6a87 100644 --- a/docs/assets/js/6.e883523c.js +++ b/docs/assets/js/6.b5dc0bcc.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[6],{354:function(t,e,n){"use strict";n.r(e);var s=n(42),l=Object(s.a)({},(function(){var t=this.$createElement;return(this._self._c||t)("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}})}),[],!1,null,null,null);e.default=l.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[6],{353:function(t,e,n){"use strict";n.r(e);var s=n(42),l=Object(s.a)({},(function(){var t=this.$createElement;return(this._self._c||t)("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}})}),[],!1,null,null,null);e.default=l.exports}}]); \ No newline at end of file diff --git a/docs/assets/js/7.e3b70354.js b/docs/assets/js/7.d2312c9e.js similarity index 81% rename from docs/assets/js/7.e3b70354.js rename to docs/assets/js/7.d2312c9e.js index 02f8ee4..7935ff5 100644 --- a/docs/assets/js/7.e3b70354.js +++ b/docs/assets/js/7.d2312c9e.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[7],{352:function(t,n,s){"use strict";s.r(n);var e=s(42),o=Object(e.a)({},(function(){var t=this.$createElement,n=this._self._c||t;return n("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}},[n("p",[this._v("coming soon")])])}),[],!1,null,null,null);n.default=o.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[7],{355:function(t,n,s){"use strict";s.r(n);var e=s(42),o=Object(e.a)({},(function(){var t=this.$createElement,n=this._self._c||t;return n("ContentSlotsDistributor",{attrs:{"slot-key":this.$parent.slotKey}},[n("p",[this._v("coming soon")])])}),[],!1,null,null,null);n.default=o.exports}}]); \ No newline at end of file diff --git a/docs/assets/js/8.a4432ff1.js b/docs/assets/js/8.645ad4e8.js similarity index 97% rename from docs/assets/js/8.a4432ff1.js rename to docs/assets/js/8.645ad4e8.js index 85a1c67..2b64b46 100644 --- a/docs/assets/js/8.a4432ff1.js +++ b/docs/assets/js/8.645ad4e8.js @@ -1 +1 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[8],{353:function(t,a,r){"use strict";r.r(a);var s=r(42),_=Object(s.a)({},(function(){var t=this,a=t.$createElement,r=t._self._c||a;return r("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[r("h2",{attrs:{id:"什么是服务编排"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#什么是服务编排"}},[t._v("#")]),t._v(" 什么是服务编排")]),t._v(" "),r("p",[t._v("服务编排主要基于现有的业务微服务使用在线配置的方式快速的生成一个聚合接口。")]),t._v(" "),r("p",[t._v("特点: 在线API设计、在线测试、快速开发")]),t._v(" "),r("h2",{attrs:{id:"举例说明"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#举例说明"}},[t._v("#")]),t._v(" 举例说明")]),t._v(" "),r("p",[t._v("订单详情页面需要展示订单信息、商品信息和用户信息。可通过配置的方式生成一个接口先后调用底层微服务的订单详情接口、商品信息接口和用户信息接口,再从这3个接口的返回结果里提取需要的字段返回给前端页面。")]),t._v(" "),r("h2",{attrs:{id:"服务编排架构"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#服务编排架构"}},[t._v("#")]),t._v(" 服务编排架构")]),t._v(" "),r("p",[r("img",{attrs:{src:"/fizz_aggregate.jpg",alt:""}})]),t._v(" "),r("h2",{attrs:{id:"适用场景"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#适用场景"}},[t._v("#")]),t._v(" 适用场景")]),t._v(" "),r("h3",{attrs:{id:"前端"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#前端"}},[t._v("#")]),t._v(" 前端")]),t._v(" "),r("p",[t._v("1、一个页面调用多个接口时,可以编排好返回聚合结果,提高页面数据的加载速度")]),t._v(" "),r("p",[t._v("2、移动设备计算能力有限,可以把数据计算或业务处理逻辑放到服务端完成,加快页面响应")]),t._v(" "),r("h3",{attrs:{id:"后端"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#后端"}},[t._v("#")]),t._v(" 后端")]),t._v(" "),r("p",[t._v("1、替换应用层的聚合接口,减少应用层的胶水代码")]),t._v(" "),r("p",[t._v("2、快速生成透传数据类型的接口")]),t._v(" "),r("p",[t._v("3、数据转换和映射")])])}),[],!1,null,null,null);a.default=_.exports}}]); \ No newline at end of file +(window.webpackJsonp=window.webpackJsonp||[]).push([[8],{351:function(t,a,r){"use strict";r.r(a);var s=r(42),_=Object(s.a)({},(function(){var t=this,a=t.$createElement,r=t._self._c||a;return r("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[r("h2",{attrs:{id:"什么是服务编排"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#什么是服务编排"}},[t._v("#")]),t._v(" 什么是服务编排")]),t._v(" "),r("p",[t._v("服务编排主要基于现有的业务微服务使用在线配置的方式快速的生成一个聚合接口。")]),t._v(" "),r("p",[t._v("特点: 在线API设计、在线测试、快速开发")]),t._v(" "),r("h2",{attrs:{id:"举例说明"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#举例说明"}},[t._v("#")]),t._v(" 举例说明")]),t._v(" "),r("p",[t._v("订单详情页面需要展示订单信息、商品信息和用户信息。可通过配置的方式生成一个接口先后调用底层微服务的订单详情接口、商品信息接口和用户信息接口,再从这3个接口的返回结果里提取需要的字段返回给前端页面。")]),t._v(" "),r("h2",{attrs:{id:"服务编排架构"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#服务编排架构"}},[t._v("#")]),t._v(" 服务编排架构")]),t._v(" "),r("p",[r("img",{attrs:{src:"/fizz_aggregate.jpg",alt:""}})]),t._v(" "),r("h2",{attrs:{id:"适用场景"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#适用场景"}},[t._v("#")]),t._v(" 适用场景")]),t._v(" "),r("h3",{attrs:{id:"前端"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#前端"}},[t._v("#")]),t._v(" 前端")]),t._v(" "),r("p",[t._v("1、一个页面调用多个接口时,可以编排好返回聚合结果,提高页面数据的加载速度")]),t._v(" "),r("p",[t._v("2、移动设备计算能力有限,可以把数据计算或业务处理逻辑放到服务端完成,加快页面响应")]),t._v(" "),r("h3",{attrs:{id:"后端"}},[r("a",{staticClass:"header-anchor",attrs:{href:"#后端"}},[t._v("#")]),t._v(" 后端")]),t._v(" "),r("p",[t._v("1、替换应用层的聚合接口,减少应用层的胶水代码")]),t._v(" "),r("p",[t._v("2、快速生成透传数据类型的接口")]),t._v(" "),r("p",[t._v("3、数据转换和映射")])])}),[],!1,null,null,null);a.default=_.exports}}]); \ No newline at end of file diff --git a/docs/assets/js/9.6a35b918.js b/docs/assets/js/9.6a35b918.js new file mode 100644 index 0000000..cea0e8a --- /dev/null +++ b/docs/assets/js/9.6a35b918.js @@ -0,0 +1 @@ +(window.webpackJsonp=window.webpackJsonp||[]).push([[9],{354:function(t,s,a){"use strict";a.r(s);var n=a(42),e=Object(n.a)({},(function(){var t=this,s=t.$createElement,a=t._self._c||s;return a("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[a("h2",{attrs:{id:"创建服务"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#创建服务"}},[t._v("#")]),t._v(" 创建服务")]),t._v(" "),a("p",[a("img",{attrs:{src:"/aggr_newservice.png",alt:""}})]),t._v(" "),a("h2",{attrs:{id:"创建聚合接口"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#创建聚合接口"}},[t._v("#")]),t._v(" 创建聚合接口")]),t._v(" "),a("p",[a("img",{attrs:{src:"/aggr_newapi0.png",alt:""}}),t._v(" "),a("img",{attrs:{src:"/aggr_newapi.png",alt:""}})]),t._v(" "),a("h2",{attrs:{id:"配置输入"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#配置输入"}},[t._v("#")]),t._v(" 配置输入")]),t._v(" "),a("p",[a("img",{attrs:{src:"/aggr_config_input.png",alt:""}})]),t._v(" "),a("ul",[a("li",[t._v("配置输入的定义包括3部分:请求头、请求体和Query参数")]),t._v(" "),a("li",[t._v("基于JSON Schema规范")]),t._v(" "),a("li",[t._v("自带校验规则")]),t._v(" "),a("li",[t._v("支持自定义脚本实现复杂的逻辑校验")])]),t._v(" "),a("p",[t._v("JSON Schema规范,详见:")]),t._v(" "),a("p",[a("a",{attrs:{href:"http://json-schema.org/specification.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("http://json-schema.org/specification.html"),a("OutboundLink")],1)]),t._v(" "),a("p",[a("a",{attrs:{href:"http://json-schema.org/understanding-json-schema/",target:"_blank",rel:"noopener noreferrer"}},[t._v("http://json-schema.org/understanding-json-schema/"),a("OutboundLink")],1)]),t._v(" "),a("h2",{attrs:{id:"配置校验结果"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#配置校验结果"}},[t._v("#")]),t._v(" 配置校验结果")]),t._v(" "),a("p",[a("img",{attrs:{src:"/aggr_config_input_validate_result.png",alt:""}})]),t._v(" "),a("ul",[a("li",[t._v("校验不通过时,Fizz会把校验失败的原因(如:订单ID不能为空)放到上下文的validateMsg字段里")]),t._v(" "),a("li",[t._v("可以自定义返回给调用方的报文格式,如 msgCode, message")]),t._v(" "),a("li",[t._v("支持自定义响应头")]),t._v(" "),a("li",[t._v("支持自定义脚本处理校验结果")])]),t._v(" "),a("h2",{attrs:{id:"配置步骤"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#配置步骤"}},[t._v("#")]),t._v(" 配置步骤")]),t._v(" "),a("h3",{attrs:{id:"配置步骤的基础信息"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#配置步骤的基础信息"}},[t._v("#")]),t._v(" 配置步骤的基础信息")]),t._v(" "),a("p",[a("img",{attrs:{src:"/aggr_config_step1.png",alt:""}})]),t._v(" "),a("h3",{attrs:{id:"配置步骤的接口入出参"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#配置步骤的接口入出参"}},[t._v("#")]),t._v(" 配置步骤的接口入出参")]),t._v(" "),a("p",[a("img",{attrs:{src:"/aggr_config_step2.png",alt:""}})]),t._v(" "),a("h3",{attrs:{id:"步骤说明"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#步骤说明"}},[t._v("#")]),t._v(" 步骤说明")]),t._v(" "),a("ul",[a("li",[t._v("一个聚合接口可包含多个步骤")]),t._v(" "),a("li",[t._v("一个步骤可包含多个请求(即调用多个接口)")]),t._v(" "),a("li",[t._v("步骤间是串联顺序执行")]),t._v(" "),a("li",[t._v("一个步骤内的多个请求并行执行")])]),t._v(" "),a("h3",{attrs:{id:"数据转换"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#数据转换"}},[t._v("#")]),t._v(" 数据转换")]),t._v(" "),a("p",[t._v("支持配置固定值,引用值和脚本")]),t._v(" "),a("h4",{attrs:{id:"固定值"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#固定值"}},[t._v("#")]),t._v(" 固定值")]),t._v(" "),a("p",[a("img",{attrs:{src:"/aggr_config_step_mapping_1.png",alt:""}})]),t._v(" "),a("h4",{attrs:{id:"引用值"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#引用值"}},[t._v("#")]),t._v(" 引用值")]),t._v(" "),a("p",[a("img",{attrs:{src:"/aggr_config_step_mapping_2.png",alt:""}})]),t._v(" "),a("h4",{attrs:{id:"脚本"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#脚本"}},[t._v("#")]),t._v(" 脚本")]),t._v(" "),a("p",[a("img",{attrs:{src:"/aggr_config_step_mapping_3.png",alt:""}})]),t._v(" "),a("p",[a("img",{attrs:{src:"/aggr_config_step_mapping_4.png",alt:""}})]),t._v(" "),a("h4",{attrs:{id:"星号"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#星号"}},[t._v("#")]),t._v(" 星号 *")]),t._v(" "),a("p",[t._v("星号通配符可以接收一个返回对象类型的引用值,返回对象里的字段会合并到目标对象里")]),t._v(" "),a("p",[a("img",{attrs:{src:"/aggr_config_step_mapping_5.png",alt:""}})]),t._v(" "),a("p",[t._v('样例:userInfo = {"userName": "Fizz", "userID": 1234}')]),t._v(" "),a("h4",{attrs:{id:"优先级与覆盖顺序"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#优先级与覆盖顺序"}},[t._v("#")]),t._v(" 优先级与覆盖顺序")]),t._v(" "),a("p",[t._v("固定值 < 引用值 < 脚本 < 星号*")]),t._v(" "),a("p",[t._v("当一个字段配置了多种类型的值时按以上顺序覆盖,星号优先级最高")]),t._v(" "),a("h4",{attrs:{id:"引用值规范"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#引用值规范"}},[t._v("#")]),t._v(" 引用值规范")]),t._v(" "),a("div",{staticClass:"language-properties extra-class"},[a("pre",{pre:!0,attrs:{class:"language-properties"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 获取入参请求头aaa的值")]),t._v("\ninput.request.headers.aaa\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 获取入参请求体bbb字段的值")]),t._v("\ninput.request.body.bbb\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 获取入参URL Query参数fff字段的值")]),t._v("\ninput.request.params.fff\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 获取步骤1里request1的请求头ccc的值")]),t._v("\nstep1.request1.request.headers.ccc\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 获取步骤1里request1的响应体ddd的值")]),t._v("\nstep1.request1.response.body.ddd\n\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 获取步骤1结果里eee的值")]),t._v("\nstep1.result.eee\n\n")])])]),a("ul",[a("li",[t._v("支持单值引用,如:string,int等")]),t._v(" "),a("li",[t._v("支持对象类型的引用")])]),t._v(" "),a("p",[t._v("input: 表示调用方的输入数据,如H5页面提交上来的参数")]),t._v(" "),a("p",[t._v("stepN.requestN: 表示步骤N里调用接口N的相关参数")]),t._v(" "),a("p",[t._v("stepN.result: 表示步骤N的转换结果")]),t._v(" "),a("h4",{attrs:{id:"fallback与预处理条件"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#fallback与预处理条件"}},[t._v("#")]),t._v(" Fallback与预处理条件")]),t._v(" "),a("p",[a("img",{attrs:{src:"/aggr_config_step_fallback.png",alt:""}})]),t._v(" "),a("p",[t._v("Fallback:")]),t._v(" "),a("p",[t._v("当调用接口发生异常(如超时、网络或系统异常)可配置fallback方案:")]),t._v(" "),a("ul",[a("li",[t._v("Stop: 终止请求并立即返回")]),t._v(" "),a("li",[t._v("Continue: 继续后续的操作,且要设置默认的fallback json")])]),t._v(" "),a("p",[t._v("预处理: 根据条件判断是否要调用接口,脚本返回true时才调用接口")]),t._v(" "),a("h4",{attrs:{id:"配置步骤结果处理"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#配置步骤结果处理"}},[t._v("#")]),t._v(" 配置步骤结果处理")]),t._v(" "),a("p",[a("img",{attrs:{src:"/aggr_config_step_result.png",alt:""}})]),t._v(" "),a("ul",[a("li",[a("p",[t._v("支持对步骤里调用的每一个接口的返回结果做数据转换,如果配置数据转换规则原样返回并存储到上下文里供后续使用")])]),t._v(" "),a("li",[a("p",[t._v("支持对步骤里调用的一个或多个接口的返回结果做处理,并把处理完的结果存储到上下文里供后续使用,不配置则不处理")])])]),t._v(" "),a("h2",{attrs:{id:"配置输出"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#配置输出"}},[t._v("#")]),t._v(" 配置输出")]),t._v(" "),a("p",[a("img",{attrs:{src:"/aggr_config_output.png",alt:""}})]),t._v(" "),a("p",[t._v("配置返回给调用方的结果")]),t._v(" "),a("ul",[a("li",[t._v("支持配置响应头")]),t._v(" "),a("li",[t._v("支持配置响应体")]),t._v(" "),a("li",[t._v("支持自定脚本处理复杂的业务逻辑")])]),t._v(" "),a("h2",{attrs:{id:"脚本-2"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#脚本-2"}},[t._v("#")]),t._v(" 脚本")]),t._v(" "),a("p",[t._v("目前支持以下脚本语言:")]),t._v(" "),a("p",[t._v("Javascript (推荐) - ECMAScript 5标准")]),t._v(" "),a("p",[t._v("JS脚本只支持单函数,且函数名不可变,在创建脚本时系统会自动生成初始模板,模板里包含相关使用说明")]),t._v(" "),a("p",[a("img",{attrs:{src:"/aggr_config_script_1.png",alt:""}})]),t._v(" "),a("p",[t._v("Groovy")]),t._v(" "),a("p",[a("img",{attrs:{src:"/aggr_config_script_2.png",alt:""}})]),t._v(" "),a("h3",{attrs:{id:"common-js-提供了操作context上下文的便捷操作函数"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#common-js-提供了操作context上下文的便捷操作函数"}},[t._v("#")]),t._v(" common.js 提供了操作context上下文的便捷操作函数")]),t._v(" "),a("div",{staticClass:"language-javascript extra-class"},[a("pre",{pre:!0,attrs:{class:"language-javascript"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/**\n * context 上下文便捷操作函数\n *\n */")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" common "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/* *********** private function begin *********** */")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 获取上下文中客户端请求对象")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token function-variable function"}},[t._v("getInputReq")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token parameter"}},[t._v("ctx")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("ctx "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("ctx"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'input'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("ctx"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'input'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'request'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" ctx"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'input'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'request'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 获取上下文步骤中请求接口的请求对象")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token function-variable function"}},[t._v("getStepReq")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token parameter"}},[t._v("ctx"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" stepName"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" requestName")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("ctx "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("stepName "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("requestName"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("ctx"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("stepName"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("ctx"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("stepName"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'requests'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("ctx"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("stepName"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'requests'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("requestName"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("ctx"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("stepName"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'requests'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("requestName"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'request'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" ctx"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("stepName"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'requests'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("requestName"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'request'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 获取上下文步骤中请求接口的响应对象")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token function-variable function"}},[t._v("getStepResp")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token parameter"}},[t._v("ctx"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" stepName"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" requestName")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("ctx "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("stepName "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("requestName"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("ctx"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("stepName"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("ctx"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("stepName"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'requests'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("ctx"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("stepName"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'requests'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("requestName"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("ctx"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("stepName"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'requests'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("requestName"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'response'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" ctx"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("stepName"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'requests'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("requestName"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'response'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/* *********** private function end *********** */")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/* *********** input begin ************ */")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/**\n * 获取客户端请求头\n * @param {*} ctx 上下文 【必填】\n * @param {*} headerName 请求头字段名 【选填】,不传时返回所有请求头\n */")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token function-variable function"}},[t._v("getInputReqHeader")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token parameter"}},[t._v("ctx"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" headerName")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" req "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("this")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("getInputReq")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ctx"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" headers "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" req"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'headers'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" headerName "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),t._v(" headers"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("headerName"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" headers"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/**\n * 获取客户端URL请求参数(query string)\n * @param {*} ctx 上下文 【必填】\n * @param {*} paramName URL参数名 【选填】,不传时返回所有请求参数\n */")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token function-variable function"}},[t._v("getInputReqParam")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token parameter"}},[t._v("ctx"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" paramName")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" req "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("this")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("getInputReq")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ctx"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" params "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" req"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'params'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" paramName "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),t._v(" params"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("paramName"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" params"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/**\n * 获取客户端请求体\n * @param {*} ctx 上下文 【必填】\n * @param {*} field 字段名 【选填】,不传时返回整个请求体\n */")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token function-variable function"}},[t._v("getInputReqBody")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token parameter"}},[t._v("ctx"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" field")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" req "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("this")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("getInputReq")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ctx"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" body "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" req"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'body'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" field "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),t._v(" body"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("field"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" body"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/**\n * 获取返回给客户端的响应头\n * @param {*} ctx 上下文 【必填】\n * @param {*} headerName 响应头字段名 【选填】,不传时返回所有响应头\n */")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token function-variable function"}},[t._v("getInputRespHeader")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token parameter"}},[t._v("ctx"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" headerName")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" req "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("this")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("getInputReq")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ctx"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" headers "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" req"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'headers'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" headerName "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),t._v(" headers"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("headerName"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" headers"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/**\n * 获取返回给客户端的响应体\n * @param {*} ctx 上下文 【必填】\n * @param {*} field 字段名 【选填】,不传时返回整个响应体\n */")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token function-variable function"}},[t._v("getInputRespBody")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token parameter"}},[t._v("ctx"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" field")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" req "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("this")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("getInputReq")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ctx"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" body "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" req"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'body'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" field "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),t._v(" body"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("field"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" body"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/* *********** input begin ************ */")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/* *********** step request begin ************ */")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/**\n * 获取步骤中调用的接口的请求头\n * @param {*} ctx 上下文 【必填】\n * @param {*} stepName 步骤名【必填】\n * @param {*} requestName 请求的接口名 【必填】\n * @param {*} headerName 请求头字段名 【选填】,不传时返回所有请求头\n */")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token function-variable function"}},[t._v("getStepReqHeader")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token parameter"}},[t._v("ctx"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" stepName"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" requestName"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" headerName")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" req "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("this")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("getStepReq")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ctx"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" stepName"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" requestName"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" headers "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" req"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'headers'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" headerName "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),t._v(" headers"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("headerName"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" headers"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/**\n * 获取步骤中调用的接口的URL参数\n * @param {*} ctx 上下文 【必填】\n * @param {*} stepName 步骤名【必填】\n * @param {*} requestName 请求的接口名 【必填】\n * @param {*} paramName URL参数名 【选填】,不传时返回所有URL参数\n */")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token function-variable function"}},[t._v("getStepReqParam")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token parameter"}},[t._v("ctx"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" stepName"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" requestName"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" paramName")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" req "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("this")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("getStepReq")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ctx"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" stepName"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" requestName"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" params "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" req"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'params'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" paramName "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),t._v(" params"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("paramName"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" params"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/**\n * 获取步骤中调用的接口的请求体\n * @param {*} ctx 上下文 【必填】\n * @param {*} stepName 步骤名【必填】\n * @param {*} requestName 请求的接口名 【必填】\n * @param {*} field 字段名 【选填】,不传时返回整个请求体\n */")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token function-variable function"}},[t._v("getStepReqBody")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token parameter"}},[t._v("ctx"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" stepName"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" requestName"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" field")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" req "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("this")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("getStepReq")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ctx"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" stepName"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" requestName"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" body "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" req"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'body'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" field "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),t._v(" body"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("field"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" body"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/**\n * 获取步骤中调用的接口的响应头\n * @param {*} ctx 上下文 【必填】\n * @param {*} stepName 步骤名【必填】\n * @param {*} requestName 请求的接口名 【必填】\n * @param {*} headerName 响应头字段名 【选填】,不传时返回所有响应头\n */")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token function-variable function"}},[t._v("getStepRespHeader")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token parameter"}},[t._v("ctx"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" stepName"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" requestName"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" headerName")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" resp "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("this")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("getStepResp")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ctx"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" stepName"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" requestName"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" headers "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" resp"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'headers'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" headerName "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),t._v(" headers"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("headerName"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" headers"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/**\n * 获取步骤中调用的接口的响应头\n * @param {*} ctx 上下文 【必填】\n * @param {*} stepName 步骤名【必填】\n * @param {*} requestName 请求的接口名 【必填】\n * @param {*} field 字段名 【选填】,不传时返回整个响应头\n */")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token function-variable function"}},[t._v("getStepRespBody")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token parameter"}},[t._v("ctx"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" stepName"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" requestName"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" field")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" resp "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("this")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),a("span",{pre:!0,attrs:{class:"token function"}},[t._v("getStepResp")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ctx"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" stepName"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" requestName"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" body "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" resp"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'body'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" field "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),t._v(" body"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("field"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" body"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/**\n * 获取步骤结果\n * @param {*} ctx 上下文 【必填】\n * @param {*} stepName 步骤名【必填】\n * @param {*} field 字段名 【选填】,不传时返回整个步骤结果对象\n */")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token function-variable function"}},[t._v("getStepResult")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token parameter"}},[t._v("ctx"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" stepName"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" field")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("ctx "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("stepName "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("ctx"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("stepName"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" result "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" ctx"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("stepName"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token string"}},[t._v("'result'")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" field "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),t._v(" result"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("field"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" result"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/* *********** step request end ************ */")]),t._v("\n\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n")])])]),a("h3",{attrs:{id:"context-js-数据结构"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#context-js-数据结构"}},[t._v("#")]),t._v(" context.js 数据结构")]),t._v(" "),a("div",{staticClass:"language-javascript extra-class"},[a("pre",{pre:!0,attrs:{class:"language-javascript"}},[a("code",[t._v("\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 上下文,用于保存客户输入输出和每个步骤的输入与输出结果")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" context "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 是否DEBUG模式")]),t._v("\n\tdebug"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("false")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n\t"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 各个操作的耗时")]),t._v("\n\telapsedTimes"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("actionName"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token number"}},[t._v("123")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 操作名称:耗时")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 客户输入和接口的返回结果")]),t._v("\n input"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n request"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n path"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('""')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n method"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"GET/POST"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n headers"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n body"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n params"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n response"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 聚合接口的响应")]),t._v("\n headers"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n body"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 步骤")]),t._v("\n step1"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n requests"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 接口1")]),t._v("\n request1"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 请求相关参数")]),t._v("\n request"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n url"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('""')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n method"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"GET/POST"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n headers"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n body"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 根据转换规则转换后的接口响应")]),t._v("\n response"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n headers"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n body"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 接口2")]),t._v("\n request2"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n request"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n url"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('""')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n method"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('"GET/POST"')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n headers"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n body"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n response"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n headers"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n body"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("//...")]),t._v("\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 步骤结果")]),t._v("\n result"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n")])])]),a("h2",{attrs:{id:"抛出异常"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#抛出异常"}},[t._v("#")]),t._v(" 抛出异常")]),t._v(" "),a("p",[t._v("当要在脚本里中止请求时可以通过以下方式来实现")]),t._v(" "),a("p",[a("img",{attrs:{src:"/aggr_config_exception.png",alt:""}})]),t._v(" "),a("p",[t._v("返回一个对象且这个对象包含一个_stopAndResponse等于true的属性,Fizz会终止后续的操作并把这个对象返回给调用方。")]),t._v(" "),a("h2",{attrs:{id:"重定向"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#重定向"}},[t._v("#")]),t._v(" 重定向")]),t._v(" "),a("p",[t._v("通过脚本可以实现重定向,脚本返回一个对象且这个对象同时包含_stopAndResponse=true和_redirectUrl属性,_redirectUrl的值为重定向的目标URL,Fizz会终止后续的操作并进行重定向。JavaScript脚本样例如下:")]),t._v(" "),a("p",[a("img",{attrs:{src:"/aggr_config_redirect.png",alt:""}})]),t._v(" "),a("h2",{attrs:{id:"配置路由"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#配置路由"}},[t._v("#")]),t._v(" 配置路由")]),t._v(" "),a("p",[t._v("至此服务编排的接口配置完成,但此时还不能通过网关访问接口,需要到网关管理-路由管理里配置路由")]),t._v(" "),a("p",[a("img",{attrs:{src:"/aggr_config_route.png",alt:""}})]),t._v(" "),a("h2",{attrs:{id:"在线测试"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#在线测试"}},[t._v("#")]),t._v(" 在线测试")]),t._v(" "),a("p",[a("img",{attrs:{src:"/aggr_config_test.png",alt:""}})]),t._v(" "),a("ul",[a("li",[t._v("支持在线实时测试")]),t._v(" "),a("li",[t._v("支持测试接口和正式接口隔离")]),t._v(" "),a("li",[t._v("支持返回上下文,可以查看整个执行过程中各个步骤及请求的输入与输出")]),t._v(" "),a("li",[t._v("支持保存历史测试记录")])]),t._v(" "),a("p",[a("img",{attrs:{src:"/aggr_config_test2.png",alt:""}})]),t._v(" "),a("p",[t._v("支持调试模式,在测试接口和正式接口均可使用,修改后重新发布可实时生效,在调试模式下会打印请求日志及报文,主要用于排查线上问题")]),t._v(" "),a("h2",{attrs:{id:"脚本执行异常"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#脚本执行异常"}},[t._v("#")]),t._v(" 脚本执行异常")]),t._v(" "),a("p",[t._v("当脚本执行异常时context里会记录异常信息")]),t._v(" "),a("ul",[a("li",[t._v("exceptionMessage 异常信息")]),t._v(" "),a("li",[t._v("exceptionStacks 异常堆栈信息")]),t._v(" "),a("li",[t._v("exceptionData 引起异常的脚本数据")])]),t._v(" "),a("div",{staticClass:"language-javascript extra-class"},[a("pre",{pre:!0,attrs:{class:"language-javascript"}},[a("code",[a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 上下文数据结构设计")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 上下文,用于保存客户输入输出和每个步骤的输入与输出结果")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" context "),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 是否DEBUG模式")]),t._v("\n\tdebug"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),a("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("false")]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\t\n\t"),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// exception info")]),t._v("\n\texceptionMessage"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('""')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\texceptionStacks"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('""')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n exceptionData"),a("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token string"}},[t._v('""')]),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// such as script source code that cause exception")]),t._v("\n\n "),a("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// ... other fields")]),t._v("\n"),a("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v(" \n")])])]),a("p",[t._v("在请求里加上returnContext=true可以返回context上下文,异常信息样例:")]),t._v(" "),a("p",[a("img",{attrs:{src:"/aggr_config_exception2.png",alt:""}})]),t._v(" "),a("h2",{attrs:{id:"导入导出"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#导入导出"}},[t._v("#")]),t._v(" 导入导出")]),t._v(" "),a("p",[a("img",{attrs:{src:"/aggr_config_import_export.png",alt:""}})]),t._v(" "),a("p",[t._v("导入导出主要用于在各个环境间同步接口配置,在开发环境配置好后导到测试环境中测试,测试完后导到生产环境进行发布")]),t._v(" "),a("h2",{attrs:{id:"发布-下线和审核"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#发布-下线和审核"}},[t._v("#")]),t._v(" 发布|下线和审核")]),t._v(" "),a("p",[a("img",{attrs:{src:"/aggr_release_1.png",alt:""}})]),t._v(" "),a("p",[a("img",{attrs:{src:"/aggr_release_2.png",alt:""}})]),t._v(" "),a("p",[t._v("目前发布|下线申请有以上两个入口。")]),t._v(" "),a("p",[a("img",{attrs:{src:"/aggr_release_rollback1.png",alt:""}})]),t._v(" "),a("p",[a("img",{attrs:{src:"/aggr_release_rollback.png",alt:""}})]),t._v(" "),a("ul",[a("li",[t._v("批量发布:对发布单里的接口进行批量发布")]),t._v(" "),a("li",[t._v("批量回滚:对发布单里的接口进行批量回滚")]),t._v(" "),a("li",[t._v("发布:实时发布到网关")]),t._v(" "),a("li",[t._v("回滚:支持回滚到历史任何一个版本,可在发布历史里指定一个版本进行回滚")]),t._v(" "),a("li",[t._v("下线:从网关删除接口,在后台可以通过发布功能再次上线")])]),t._v(" "),a("h3",{attrs:{id:"发布流程说明"}},[a("a",{staticClass:"header-anchor",attrs:{href:"#发布流程说明"}},[t._v("#")]),t._v(" 发布流程说明")]),t._v(" "),a("p",[t._v("申请发布、审核、发布和下线功能的权限可根据需要灵活分配给不同角色,如:开发人员只能申请发布,上级领导审核,运维或测试人员执行发布、回滚或下线。在开发、测试和预生产环境为了方便开发人员调试也可把申请发布、审核、发布和下线功能都分配给开发人员。")])])}),[],!1,null,null,null);s.default=e.exports}}]); \ No newline at end of file diff --git a/docs/assets/js/9.b1740bdf.js b/docs/assets/js/9.b1740bdf.js deleted file mode 100644 index 296f3f9..0000000 --- a/docs/assets/js/9.b1740bdf.js +++ /dev/null @@ -1 +0,0 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[9],{355:function(t,a,s){"use strict";s.r(a);var n=s(42),e=Object(n.a)({},(function(){var t=this,a=t.$createElement,s=t._self._c||a;return s("ContentSlotsDistributor",{attrs:{"slot-key":t.$parent.slotKey}},[s("h2",{attrs:{id:"创建服务"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#创建服务"}},[t._v("#")]),t._v(" 创建服务")]),t._v(" "),s("p",[s("img",{attrs:{src:"/aggr_newservice.png",alt:""}})]),t._v(" "),s("h2",{attrs:{id:"创建聚合接口"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#创建聚合接口"}},[t._v("#")]),t._v(" 创建聚合接口")]),t._v(" "),s("p",[s("img",{attrs:{src:"/aggr_newapi0.png",alt:""}}),t._v(" "),s("img",{attrs:{src:"/aggr_newapi.png",alt:""}})]),t._v(" "),s("h2",{attrs:{id:"配置输入"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#配置输入"}},[t._v("#")]),t._v(" 配置输入")]),t._v(" "),s("p",[s("img",{attrs:{src:"/aggr_config_input.png",alt:""}})]),t._v(" "),s("ul",[s("li",[t._v("配置输入的定义包括3部分:请求头、请求体和Query参数")]),t._v(" "),s("li",[t._v("基于JSON Schema规范")]),t._v(" "),s("li",[t._v("自带校验规则")]),t._v(" "),s("li",[t._v("支持自定义脚本实现复杂的逻辑校验")])]),t._v(" "),s("p",[t._v("JSON Schema规范,详见:")]),t._v(" "),s("p",[s("a",{attrs:{href:"http://json-schema.org/specification.html",target:"_blank",rel:"noopener noreferrer"}},[t._v("http://json-schema.org/specification.html"),s("OutboundLink")],1)]),t._v(" "),s("p",[s("a",{attrs:{href:"http://json-schema.org/understanding-json-schema/",target:"_blank",rel:"noopener noreferrer"}},[t._v("http://json-schema.org/understanding-json-schema/"),s("OutboundLink")],1)]),t._v(" "),s("h2",{attrs:{id:"配置校验结果"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#配置校验结果"}},[t._v("#")]),t._v(" 配置校验结果")]),t._v(" "),s("p",[s("img",{attrs:{src:"/aggr_config_input_validate_result.png",alt:""}})]),t._v(" "),s("ul",[s("li",[t._v("校验不通过时,Fizz会把校验失败的原因(如:订单ID不能为空)放到上下文的validateMsg字段里")]),t._v(" "),s("li",[t._v("可以自定义返回给调用方的报文格式,如 msgCode, message")]),t._v(" "),s("li",[t._v("支持自定义响应头")]),t._v(" "),s("li",[t._v("支持自定义脚本处理校验结果")])]),t._v(" "),s("h2",{attrs:{id:"配置步骤"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#配置步骤"}},[t._v("#")]),t._v(" 配置步骤")]),t._v(" "),s("h3",{attrs:{id:"配置步骤的基础信息"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#配置步骤的基础信息"}},[t._v("#")]),t._v(" 配置步骤的基础信息")]),t._v(" "),s("p",[s("img",{attrs:{src:"/aggr_config_step1.png",alt:""}})]),t._v(" "),s("h3",{attrs:{id:"配置步骤的接口入出参"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#配置步骤的接口入出参"}},[t._v("#")]),t._v(" 配置步骤的接口入出参")]),t._v(" "),s("p",[s("img",{attrs:{src:"/aggr_config_step2.png",alt:""}})]),t._v(" "),s("h3",{attrs:{id:"步骤说明"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#步骤说明"}},[t._v("#")]),t._v(" 步骤说明")]),t._v(" "),s("ul",[s("li",[t._v("一个聚合接口可包含多个步骤")]),t._v(" "),s("li",[t._v("一个步骤可包含多个请求(即调用多个接口)")]),t._v(" "),s("li",[t._v("步骤间是串联顺序执行")]),t._v(" "),s("li",[t._v("一个步骤内的多个请求并行执行")])]),t._v(" "),s("h3",{attrs:{id:"数据转换"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#数据转换"}},[t._v("#")]),t._v(" 数据转换")]),t._v(" "),s("p",[t._v("支持配置固定值,引用值和脚本")]),t._v(" "),s("h4",{attrs:{id:"固定值"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#固定值"}},[t._v("#")]),t._v(" 固定值")]),t._v(" "),s("p",[s("img",{attrs:{src:"/aggr_config_step_mapping_1.png",alt:""}})]),t._v(" "),s("h4",{attrs:{id:"引用值"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#引用值"}},[t._v("#")]),t._v(" 引用值")]),t._v(" "),s("p",[s("img",{attrs:{src:"/aggr_config_step_mapping_2.png",alt:""}})]),t._v(" "),s("h4",{attrs:{id:"脚本"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#脚本"}},[t._v("#")]),t._v(" 脚本")]),t._v(" "),s("p",[s("img",{attrs:{src:"/aggr_config_step_mapping_3.png",alt:""}})]),t._v(" "),s("p",[s("img",{attrs:{src:"/aggr_config_step_mapping_4.png",alt:""}})]),t._v(" "),s("h4",{attrs:{id:"星号"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#星号"}},[t._v("#")]),t._v(" 星号 *")]),t._v(" "),s("p",[t._v("星号通配符可以接收一个返回对象类型的引用值,返回对象里的字段会合并到目标对象里")]),t._v(" "),s("p",[s("img",{attrs:{src:"/aggr_config_step_mapping_5.png",alt:""}})]),t._v(" "),s("p",[t._v('样例:userInfo = {"userName": "Fizz", "userID": 1234}')]),t._v(" "),s("h4",{attrs:{id:"优先级与覆盖顺序"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#优先级与覆盖顺序"}},[t._v("#")]),t._v(" 优先级与覆盖顺序")]),t._v(" "),s("p",[t._v("固定值 < 引用值 < 脚本 < 星号*")]),t._v(" "),s("p",[t._v("当一个字段配置了多种类型的值时按以上顺序覆盖,星号优先级最高")]),t._v(" "),s("h4",{attrs:{id:"引用值规范"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#引用值规范"}},[t._v("#")]),t._v(" 引用值规范")]),t._v(" "),s("div",{staticClass:"language-properties extra-class"},[s("pre",{pre:!0,attrs:{class:"language-properties"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 获取入参请求头aaa的值")]),t._v("\ninput.request.headers.aaa\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 获取入参请求体bbb字段的值")]),t._v("\ninput.request.body.bbb\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 获取入参URL Query参数fff字段的值")]),t._v("\ninput.request.params.fff\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 获取步骤1里request1的请求头ccc的值")]),t._v("\nstep1.request1.request.headers.ccc\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 获取步骤1里request1的响应体ddd的值")]),t._v("\nstep1.request1.response.body.ddd\n\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("# 获取步骤1结果里eee的值")]),t._v("\nstep1.result.eee\n\n")])])]),s("ul",[s("li",[t._v("支持单值引用,如:string,int等")]),t._v(" "),s("li",[t._v("支持对象类型的引用")])]),t._v(" "),s("p",[t._v("input: 表示调用方的输入数据,如H5页面提交上来的参数")]),t._v(" "),s("p",[t._v("stepN.requestN: 表示步骤N里调用接口N的相关参数")]),t._v(" "),s("p",[t._v("stepN.result: 表示步骤N的转换结果")]),t._v(" "),s("h4",{attrs:{id:"fallback与预处理条件"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#fallback与预处理条件"}},[t._v("#")]),t._v(" Fallback与预处理条件")]),t._v(" "),s("p",[s("img",{attrs:{src:"/aggr_config_step_fallback.png",alt:""}})]),t._v(" "),s("p",[t._v("Fallback:")]),t._v(" "),s("p",[t._v("当调用接口发生异常(如超时、网络或系统异常)可配置fallback方案:")]),t._v(" "),s("ul",[s("li",[t._v("Stop: 终止请求并立即返回")]),t._v(" "),s("li",[t._v("Continue: 继续后续的操作,且要设置默认的fallback json")])]),t._v(" "),s("p",[t._v("预处理: 根据条件判断是否要调用接口,脚本返回true时才调用接口")]),t._v(" "),s("h4",{attrs:{id:"配置步骤结果处理"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#配置步骤结果处理"}},[t._v("#")]),t._v(" 配置步骤结果处理")]),t._v(" "),s("p",[s("img",{attrs:{src:"/aggr_config_step_result.png",alt:""}})]),t._v(" "),s("ul",[s("li",[s("p",[t._v("支持对步骤里调用的每一个接口的返回结果做数据转换,如果配置数据转换规则原样返回并存储到上下文里供后续使用")])]),t._v(" "),s("li",[s("p",[t._v("支持对步骤里调用的一个或多个接口的返回结果做处理,并把处理完的结果存储到上下文里供后续使用,不配置则不处理")])])]),t._v(" "),s("h2",{attrs:{id:"配置输出"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#配置输出"}},[t._v("#")]),t._v(" 配置输出")]),t._v(" "),s("p",[s("img",{attrs:{src:"/aggr_config_output.png",alt:""}})]),t._v(" "),s("p",[t._v("配置返回给调用方的结果")]),t._v(" "),s("ul",[s("li",[t._v("支持配置响应头")]),t._v(" "),s("li",[t._v("支持配置响应体")]),t._v(" "),s("li",[t._v("支持自定脚本处理复杂的业务逻辑")])]),t._v(" "),s("h2",{attrs:{id:"脚本-2"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#脚本-2"}},[t._v("#")]),t._v(" 脚本")]),t._v(" "),s("p",[t._v("目前支持以下脚本语言:")]),t._v(" "),s("p",[t._v("Javascript (推荐) - ECMAScript 5标准")]),t._v(" "),s("p",[t._v("JS脚本只支持单函数,且函数名不可变,在创建脚本时系统会自动生成初始模板,模板里包含相关使用说明")]),t._v(" "),s("p",[s("img",{attrs:{src:"/aggr_config_script_1.png",alt:""}})]),t._v(" "),s("p",[t._v("Groovy")]),t._v(" "),s("p",[s("img",{attrs:{src:"/aggr_config_script_2.png",alt:""}})]),t._v(" "),s("h3",{attrs:{id:"common-js-提供了操作context上下文的便捷操作函数"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#common-js-提供了操作context上下文的便捷操作函数"}},[t._v("#")]),t._v(" common.js 提供了操作context上下文的便捷操作函数")]),t._v(" "),s("div",{staticClass:"language-javascript extra-class"},[s("pre",{pre:!0,attrs:{class:"language-javascript"}},[s("code",[s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/**\n * context 上下文便捷操作函数\n *\n */")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" common "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/* *********** private function begin *********** */")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 获取上下文中客户端请求对象")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token function-variable function"}},[t._v("getInputReq")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token parameter"}},[t._v("ctx")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("ctx "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'input'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'input'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'request'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'input'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'request'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 获取上下文步骤中请求接口的请求对象")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token function-variable function"}},[t._v("getStepReq")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token parameter"}},[t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" stepName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" requestName")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("ctx "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("stepName "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("requestName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("stepName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("stepName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'requests'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("stepName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'requests'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("requestName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("stepName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'requests'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("requestName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'request'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("stepName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'requests'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("requestName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'request'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 获取上下文步骤中请求接口的响应对象")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token function-variable function"}},[t._v("getStepResp")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token parameter"}},[t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" stepName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" requestName")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("ctx "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("stepName "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("requestName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("stepName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("stepName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'requests'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("stepName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'requests'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("requestName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("stepName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'requests'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("requestName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'response'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("stepName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'requests'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("requestName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'response'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/* *********** private function end *********** */")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/* *********** input begin ************ */")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/**\n * 获取客户端请求头\n * @param {*} ctx 上下文 【必填】\n * @param {*} headerName 请求头字段名 【选填】,不传时返回所有请求头\n */")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token function-variable function"}},[t._v("getInputReqHeader")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token parameter"}},[t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" headerName")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" req "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("this")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getInputReq")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" headers "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" req"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'headers'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" headerName "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),t._v(" headers"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("headerName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" headers"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/**\n * 获取客户端URL请求参数(query string)\n * @param {*} ctx 上下文 【必填】\n * @param {*} paramName URL参数名 【选填】,不传时返回所有请求参数\n */")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token function-variable function"}},[t._v("getInputReqParam")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token parameter"}},[t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" paramName")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" req "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("this")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getInputReq")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" params "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" req"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'params'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" paramName "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),t._v(" params"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("paramName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" params"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/**\n * 获取客户端请求体\n * @param {*} ctx 上下文 【必填】\n * @param {*} field 字段名 【选填】,不传时返回整个请求体\n */")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token function-variable function"}},[t._v("getInputReqBody")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token parameter"}},[t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" field")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" req "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("this")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getInputReq")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" body "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" req"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'body'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" field "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),t._v(" body"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("field"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" body"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/**\n * 获取返回给客户端的响应头\n * @param {*} ctx 上下文 【必填】\n * @param {*} headerName 响应头字段名 【选填】,不传时返回所有响应头\n */")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token function-variable function"}},[t._v("getInputRespHeader")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token parameter"}},[t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" headerName")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" req "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("this")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getInputReq")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" headers "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" req"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'headers'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" headerName "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),t._v(" headers"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("headerName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" headers"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/**\n * 获取返回给客户端的响应体\n * @param {*} ctx 上下文 【必填】\n * @param {*} field 字段名 【选填】,不传时返回整个响应体\n */")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token function-variable function"}},[t._v("getInputRespBody")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token parameter"}},[t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" field")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" req "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("this")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getInputReq")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" body "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" req"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'body'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" field "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),t._v(" body"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("field"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" body"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/* *********** input begin ************ */")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/* *********** step request begin ************ */")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/**\n * 获取步骤中调用的接口的请求头\n * @param {*} ctx 上下文 【必填】\n * @param {*} stepName 步骤名【必填】\n * @param {*} requestName 请求的接口名 【必填】\n * @param {*} headerName 请求头字段名 【选填】,不传时返回所有请求头\n */")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token function-variable function"}},[t._v("getStepReqHeader")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token parameter"}},[t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" stepName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" requestName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" headerName")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" req "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("this")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getStepReq")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" stepName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" requestName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" headers "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" req"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'headers'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" headerName "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),t._v(" headers"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("headerName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" headers"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/**\n * 获取步骤中调用的接口的URL参数\n * @param {*} ctx 上下文 【必填】\n * @param {*} stepName 步骤名【必填】\n * @param {*} requestName 请求的接口名 【必填】\n * @param {*} paramName URL参数名 【选填】,不传时返回所有URL参数\n */")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token function-variable function"}},[t._v("getStepReqParam")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token parameter"}},[t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" stepName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" requestName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" paramName")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" req "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("this")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getStepReq")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" stepName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" requestName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" params "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" req"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'params'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" paramName "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),t._v(" params"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("paramName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" params"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/**\n * 获取步骤中调用的接口的请求体\n * @param {*} ctx 上下文 【必填】\n * @param {*} stepName 步骤名【必填】\n * @param {*} requestName 请求的接口名 【必填】\n * @param {*} field 字段名 【选填】,不传时返回整个请求体\n */")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token function-variable function"}},[t._v("getStepReqBody")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token parameter"}},[t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" stepName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" requestName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" field")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" req "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("this")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getStepReq")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" stepName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" requestName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" body "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" req"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'body'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" field "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),t._v(" body"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("field"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" body"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/**\n * 获取步骤中调用的接口的响应头\n * @param {*} ctx 上下文 【必填】\n * @param {*} stepName 步骤名【必填】\n * @param {*} requestName 请求的接口名 【必填】\n * @param {*} headerName 响应头字段名 【选填】,不传时返回所有响应头\n */")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token function-variable function"}},[t._v("getStepRespHeader")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token parameter"}},[t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" stepName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" requestName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" headerName")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" resp "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("this")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getStepResp")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" stepName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" requestName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" headers "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" resp"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'headers'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" headerName "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),t._v(" headers"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("headerName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" headers"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/**\n * 获取步骤中调用的接口的响应头\n * @param {*} ctx 上下文 【必填】\n * @param {*} stepName 步骤名【必填】\n * @param {*} requestName 请求的接口名 【必填】\n * @param {*} field 字段名 【选填】,不传时返回整个响应头\n */")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token function-variable function"}},[t._v("getStepRespBody")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token parameter"}},[t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" stepName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" requestName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" field")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" resp "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("this")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(".")]),s("span",{pre:!0,attrs:{class:"token function"}},[t._v("getStepResp")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" stepName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" requestName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" body "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" resp"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'body'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" field "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),t._v(" body"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("field"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" body"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/**\n * 获取步骤结果\n * @param {*} ctx 上下文 【必填】\n * @param {*} stepName 步骤名【必填】\n * @param {*} field 字段名 【选填】,不传时返回整个步骤结果对象\n */")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token function-variable function"}},[t._v("getStepResult")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("function")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token parameter"}},[t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" stepName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" field")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("if")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("(")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("ctx "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("stepName "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("!")]),t._v("ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("stepName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(")")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" result "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" ctx"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("stepName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token string"}},[t._v("'result'")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("||")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("return")]),t._v(" field "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("?")]),t._v(" result"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("field"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" result"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("/* *********** step request end ************ */")]),t._v("\n\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n")])])]),s("h3",{attrs:{id:"context-js-数据结构"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#context-js-数据结构"}},[t._v("#")]),t._v(" context.js 数据结构")]),t._v(" "),s("div",{staticClass:"language-javascript extra-class"},[s("pre",{pre:!0,attrs:{class:"language-javascript"}},[s("code",[t._v("\n"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 上下文,用于保存客户输入输出和每个步骤的输入与输出结果")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token keyword"}},[t._v("var")]),t._v(" context "),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v("=")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 是否DEBUG模式")]),t._v("\n\tdebug"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),s("span",{pre:!0,attrs:{class:"token boolean"}},[t._v("false")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n\t"),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 各个操作的耗时")]),t._v("\n\telapsedTimes"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n\t\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("[")]),t._v("actionName"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token number"}},[t._v("123")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 操作名称:耗时")]),t._v("\n\t"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("]")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 客户输入和接口的返回结果")]),t._v("\n input"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n request"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n path"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('""')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n method"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"GET/POST"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n headers"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n body"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n params"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n response"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 聚合接口的响应")]),t._v("\n headers"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n body"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 步骤")]),t._v("\n step1"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n requests"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 接口1")]),t._v("\n request1"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 请求相关参数")]),t._v("\n request"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n url"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('""')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n method"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"GET/POST"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n headers"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n body"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 根据转换规则转换后的接口响应")]),t._v("\n response"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n headers"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n body"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 接口2")]),t._v("\n request2"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n request"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n url"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('""')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n method"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token string"}},[t._v('"GET/POST"')]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n headers"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n body"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n response"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),t._v("\n headers"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n body"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("//...")]),t._v("\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(",")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token comment"}},[t._v("// 步骤结果")]),t._v("\n result"),s("span",{pre:!0,attrs:{class:"token operator"}},[t._v(":")]),t._v(" "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("{")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n\n "),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),t._v("\n"),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v("}")]),s("span",{pre:!0,attrs:{class:"token punctuation"}},[t._v(";")]),t._v("\n\n")])])]),s("h2",{attrs:{id:"异常处理"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#异常处理"}},[t._v("#")]),t._v(" 异常处理")]),t._v(" "),s("p",[t._v("当要在脚本里中止请求时可以通过以下方式来实现")]),t._v(" "),s("p",[s("img",{attrs:{src:"/aggr_config_exception.png",alt:""}})]),t._v(" "),s("p",[t._v("返回一个对象且这个对象包含一个_stopAndResponse等于true的属性,Fizz会终止后续的操作并把这个对象返回给调用方。")]),t._v(" "),s("h2",{attrs:{id:"重定向"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#重定向"}},[t._v("#")]),t._v(" 重定向")]),t._v(" "),s("p",[t._v("通过脚本可以实现重定向,脚本返回一个对象且这个对象同时包含_stopAndResponse=true和_redirectUrl属性,_redirectUrl的值为重定向的目标URL,Fizz会终止后续的操作并进行重定向。JavaScript脚本样例如下:")]),t._v(" "),s("p",[s("img",{attrs:{src:"/aggr_config_redirect.png",alt:""}})]),t._v(" "),s("h2",{attrs:{id:"配置路由"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#配置路由"}},[t._v("#")]),t._v(" 配置路由")]),t._v(" "),s("p",[t._v("至此服务编排的接口配置完成,但此时还不能通过网关访问接口,需要到网关管理-路由管理里配置路由")]),t._v(" "),s("p",[s("img",{attrs:{src:"/aggr_config_route.png",alt:""}})]),t._v(" "),s("h2",{attrs:{id:"在线测试"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#在线测试"}},[t._v("#")]),t._v(" 在线测试")]),t._v(" "),s("p",[s("img",{attrs:{src:"/aggr_config_test.png",alt:""}})]),t._v(" "),s("ul",[s("li",[t._v("支持在线实时测试")]),t._v(" "),s("li",[t._v("支持测试接口和正式接口隔离")]),t._v(" "),s("li",[t._v("支持返回上下文,可以查看整个执行过程中各个步骤及请求的输入与输出")]),t._v(" "),s("li",[t._v("支持保存历史测试记录")])]),t._v(" "),s("p",[s("img",{attrs:{src:"/aggr_config_test2.png",alt:""}})]),t._v(" "),s("p",[t._v("支持调试模式,在测试接口和正式接口均可使用,修改后重新发布可实时生效,在调试模式下会打印请求日志及报文,主要用于排查线上问题")]),t._v(" "),s("h2",{attrs:{id:"导入导出"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#导入导出"}},[t._v("#")]),t._v(" 导入导出")]),t._v(" "),s("p",[s("img",{attrs:{src:"/aggr_config_import_export.png",alt:""}})]),t._v(" "),s("p",[t._v("导入导出主要用于在各个环境间同步接口配置,在开发环境配置好后导到测试环境中测试,测试完后导到生产环境进行发布")]),t._v(" "),s("h2",{attrs:{id:"发布-下线和审核"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#发布-下线和审核"}},[t._v("#")]),t._v(" 发布|下线和审核")]),t._v(" "),s("p",[s("img",{attrs:{src:"/aggr_release_1.png",alt:""}})]),t._v(" "),s("p",[s("img",{attrs:{src:"/aggr_release_2.png",alt:""}})]),t._v(" "),s("p",[t._v("目前发布|下线申请有以上两个入口。")]),t._v(" "),s("p",[s("img",{attrs:{src:"/aggr_release_rollback1.png",alt:""}})]),t._v(" "),s("p",[s("img",{attrs:{src:"/aggr_release_rollback.png",alt:""}})]),t._v(" "),s("ul",[s("li",[t._v("批量发布:对发布单里的接口进行批量发布")]),t._v(" "),s("li",[t._v("批量回滚:对发布单里的接口进行批量回滚")]),t._v(" "),s("li",[t._v("发布:实时发布到网关")]),t._v(" "),s("li",[t._v("回滚:支持回滚到历史任何一个版本,可在发布历史里指定一个版本进行回滚")]),t._v(" "),s("li",[t._v("下线:从网关删除接口,在后台可以通过发布功能再次上线")])]),t._v(" "),s("h3",{attrs:{id:"发布流程说明"}},[s("a",{staticClass:"header-anchor",attrs:{href:"#发布流程说明"}},[t._v("#")]),t._v(" 发布流程说明")]),t._v(" "),s("p",[t._v("申请发布、审核、发布和下线功能的权限可根据需要灵活分配给不同角色,如:开发人员只能申请发布,上级领导审核,运维或测试人员执行发布、回滚或下线。在开发、测试和预生产环境为了方便开发人员调试也可把申请发布、审核、发布和下线功能都分配给开发人员。")])])}),[],!1,null,null,null);a.default=e.exports}}]); \ No newline at end of file diff --git a/docs/assets/js/app.60575df2.js b/docs/assets/js/app.307fd529.js similarity index 75% rename from docs/assets/js/app.60575df2.js rename to docs/assets/js/app.307fd529.js index 2c5a1d8..d44d2d1 100644 --- a/docs/assets/js/app.60575df2.js +++ b/docs/assets/js/app.307fd529.js @@ -1,4 +1,4 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[0],[]]);!function(t){function e(e){for(var r,a,u=e[0],c=e[1],s=e[2],f=0,p=[];f0?o(r(t),9007199254740991):0}},function(t,e){var n=Array.isArray;t.exports=n},function(t,e,n){var r=n(31),o=n(23);t.exports=function(t){return r(o(t))}},function(t,e,n){var r=n(140),o="object"==typeof self&&self&&self.Object===Object&&self,i=r||o||Function("return this")();t.exports=i},function(t,e,n){var r=n(6),o=n(1),i=n(7),a=Object.defineProperty,u={},c=function(t){throw t};t.exports=function(t,e){if(i(u,t))return u[t];e||(e={});var n=[][t],s=!!i(e,"ACCESSORS")&&e.ACCESSORS,l=i(e,0)?e[0]:c,f=i(e,1)?e[1]:void 0;return u[t]=!!n&&!o((function(){if(s&&!r)return!0;var t={length:-1};s?a(t,1,{enumerable:!0,get:c}):t[1]=1,n.call(t,l,f)}))}},function(t,e){var n={}.toString;t.exports=function(t){return n.call(t).slice(8,-1)}},function(t,e,n){var r=n(110),o=n(3),i=function(t){return"function"==typeof t?t:void 0};t.exports=function(t,e){return arguments.length<2?i(r[t])||i(o[t]):r[t]&&r[t][e]||o[t]&&o[t][e]}},function(t,e){t.exports=!1},function(t,e){t.exports=function(t){if("function"!=typeof t)throw TypeError(String(t)+" is not a function");return t}},function(t,e,n){var r=n(220),o=n(223);t.exports=function(t,e){var n=o(t,e);return r(n)?n:void 0}},function(t,e){t.exports=function(t){if(null==t)throw TypeError("Can't call method on "+t);return t}},function(t,e,n){"use strict";var r=n(0),o=n(29).filter,i=n(51),a=n(17),u=i("filter"),c=a("filter");r({target:"Array",proto:!0,forced:!u||!c},{filter:function(t){return o(this,t,arguments.length>1?arguments[1]:void 0)}})},function(t,e,n){var r=n(6),o=n(75),i=n(32),a=n(15),u=n(44),c=n(7),s=n(105),l=Object.getOwnPropertyDescriptor;e.f=r?l:function(t,e){if(t=a(t),e=u(e,!0),s)try{return l(t,e)}catch(t){}if(c(t,e))return i(!o.f.call(t,e),t[e])}},function(t,e){t.exports=function(t){return null!=t&&"object"==typeof t}},function(t,e,n){"use strict";var r=n(128).charAt,o=n(28),i=n(111),a=o.set,u=o.getterFor("String Iterator");i(String,"String",(function(t){a(this,{type:"String Iterator",string:String(t),index:0})}),(function(){var t,e=u(this),n=e.string,o=e.index;return o>=n.length?{value:void 0,done:!0}:(t=r(n,o),e.index+=t.length,{value:t,done:!1})}))},function(t,e,n){var r,o,i,a=n(180),u=n(3),c=n(4),s=n(11),l=n(7),f=n(48),p=n(34),d=u.WeakMap;if(a){var h=new d,v=h.get,g=h.has,m=h.set;r=function(t,e){return m.call(h,t,e),e},o=function(t){return v.call(h,t)||{}},i=function(t){return g.call(h,t)}}else{var y=f("state");p[y]=!0,r=function(t,e){return s(t,y,e),e},o=function(t){return l(t,y)?t[y]:{}},i=function(t){return l(t,y)}}t.exports={set:r,get:o,has:i,enforce:function(t){return i(t)?o(t):r(t,{})},getterFor:function(t){return function(e){var n;if(!c(e)||(n=o(e)).type!==t)throw TypeError("Incompatible receiver, "+t+" required");return n}}}},function(t,e,n){var r=n(50),o=n(31),i=n(12),a=n(13),u=n(127),c=[].push,s=function(t){var e=1==t,n=2==t,s=3==t,l=4==t,f=6==t,p=5==t||f;return function(d,h,v,g){for(var m,y,b=i(d),_=o(b),x=r(h,v,3),w=a(_.length),O=0,S=g||u,j=e?S(d,w):n?S(d,0):void 0;w>O;O++)if((p||O in _)&&(y=x(m=_[O],O,b),t))if(e)j[O]=y;else if(y)switch(t){case 3:return!0;case 5:return m;case 6:return O;case 2:c.call(j,m)}else if(l)return!1;return f?-1:s||l?l:j}};t.exports={forEach:s(0),map:s(1),filter:s(2),some:s(3),every:s(4),find:s(5),findIndex:s(6)}},function(t,e,n){var r=n(39),o=n(205),i=n(206),a=r?r.toStringTag:void 0;t.exports=function(t){return null==t?void 0===t?"[object Undefined]":"[object Null]":a&&a in Object(t)?o(t):i(t)}},function(t,e,n){var r=n(1),o=n(18),i="".split;t.exports=r((function(){return!Object("z").propertyIsEnumerable(0)}))?function(t){return"String"==o(t)?i.call(t,""):Object(t)}:Object},function(t,e){t.exports=function(t,e){return{enumerable:!(1&t),configurable:!(2&t),writable:!(4&t),value:e}}},function(t,e,n){var r,o=n(5),i=n(179),a=n(73),u=n(34),c=n(109),s=n(70),l=n(48),f=l("IE_PROTO"),p=function(){},d=function(t){return" +

coming soon

上次更新: 2020-9-8 15:3
+ diff --git a/docs/guide/aggregate/configuration.html b/docs/guide/aggregate/configuration.html index 3bb2aa4..d8291a1 100644 --- a/docs/guide/aggregate/configuration.html +++ b/docs/guide/aggregate/configuration.html @@ -7,7 +7,7 @@ - + @@ -23,7 +23,7 @@ 使用文档
查看源码 -

# 创建服务

# 创建聚合接口

# 配置输入

  • 配置输入的定义包括3部分:请求头、请求体和Query参数
  • 基于JSON Schema规范
  • 自带校验规则
  • 支持自定义脚本实现复杂的逻辑校验

JSON Schema规范,详见:

http://json-schema.org/specification.html

http://json-schema.org/understanding-json-schema/

# 配置校验结果

  • 校验不通过时,Fizz会把校验失败的原因(如:订单ID不能为空)放到上下文的validateMsg字段里
  • 可以自定义返回给调用方的报文格式,如 msgCode, message
  • 支持自定义响应头
  • 支持自定义脚本处理校验结果

# 配置步骤

# 配置步骤的基础信息

# 配置步骤的接口入出参

# 步骤说明

  • 一个聚合接口可包含多个步骤
  • 一个步骤可包含多个请求(即调用多个接口)
  • 步骤间是串联顺序执行
  • 一个步骤内的多个请求并行执行

# 数据转换

支持配置固定值,引用值和脚本

# 固定值

# 引用值

# 脚本

# 星号 *

星号通配符可以接收一个返回对象类型的引用值,返回对象里的字段会合并到目标对象里

样例:userInfo = {"userName": "Fizz", "userID": 1234}

# 优先级与覆盖顺序

固定值 < 引用值 < 脚本 < 星号*

当一个字段配置了多种类型的值时按以上顺序覆盖,星号优先级最高

# 引用值规范

# 获取入参请求头aaa的值
+        

# 创建服务

# 创建聚合接口

# 配置输入

  • 配置输入的定义包括3部分:请求头、请求体和Query参数
  • 基于JSON Schema规范
  • 自带校验规则
  • 支持自定义脚本实现复杂的逻辑校验

JSON Schema规范,详见:

http://json-schema.org/specification.html

http://json-schema.org/understanding-json-schema/

# 配置校验结果

  • 校验不通过时,Fizz会把校验失败的原因(如:订单ID不能为空)放到上下文的validateMsg字段里
  • 可以自定义返回给调用方的报文格式,如 msgCode, message
  • 支持自定义响应头
  • 支持自定义脚本处理校验结果

# 配置步骤

# 配置步骤的基础信息

# 配置步骤的接口入出参

# 步骤说明

  • 一个聚合接口可包含多个步骤
  • 一个步骤可包含多个请求(即调用多个接口)
  • 步骤间是串联顺序执行
  • 一个步骤内的多个请求并行执行

# 数据转换

支持配置固定值,引用值和脚本

# 固定值

# 引用值

# 脚本

# 星号 *

星号通配符可以接收一个返回对象类型的引用值,返回对象里的字段会合并到目标对象里

样例:userInfo = {"userName": "Fizz", "userID": 1234}

# 优先级与覆盖顺序

固定值 < 引用值 < 脚本 < 星号*

当一个字段配置了多种类型的值时按以上顺序覆盖,星号优先级最高

# 引用值规范

# 获取入参请求头aaa的值
 input.request.headers.aaa
 
 # 获取入参请求体bbb字段的值
@@ -292,7 +292,20 @@ step1.result.eee
   }
 };
 
-

# 异常处理

当要在脚本里中止请求时可以通过以下方式来实现

返回一个对象且这个对象包含一个_stopAndResponse等于true的属性,Fizz会终止后续的操作并把这个对象返回给调用方。

# 重定向

通过脚本可以实现重定向,脚本返回一个对象且这个对象同时包含_stopAndResponse=true和_redirectUrl属性,_redirectUrl的值为重定向的目标URL,Fizz会终止后续的操作并进行重定向。JavaScript脚本样例如下:

# 配置路由

至此服务编排的接口配置完成,但此时还不能通过网关访问接口,需要到网关管理-路由管理里配置路由

# 在线测试

  • 支持在线实时测试
  • 支持测试接口和正式接口隔离
  • 支持返回上下文,可以查看整个执行过程中各个步骤及请求的输入与输出
  • 支持保存历史测试记录

支持调试模式,在测试接口和正式接口均可使用,修改后重新发布可实时生效,在调试模式下会打印请求日志及报文,主要用于排查线上问题

# 导入导出

导入导出主要用于在各个环境间同步接口配置,在开发环境配置好后导到测试环境中测试,测试完后导到生产环境进行发布

# 发布|下线和审核

目前发布|下线申请有以上两个入口。

  • 批量发布:对发布单里的接口进行批量发布
  • 批量回滚:对发布单里的接口进行批量回滚
  • 发布:实时发布到网关
  • 回滚:支持回滚到历史任何一个版本,可在发布历史里指定一个版本进行回滚
  • 下线:从网关删除接口,在后台可以通过发布功能再次上线

# 发布流程说明

申请发布、审核、发布和下线功能的权限可根据需要灵活分配给不同角色,如:开发人员只能申请发布,上级领导审核,运维或测试人员执行发布、回滚或下线。在开发、测试和预生产环境为了方便开发人员调试也可把申请发布、审核、发布和下线功能都分配给开发人员。

上次更新: 2020-11-18 15:16

# 抛出异常

当要在脚本里中止请求时可以通过以下方式来实现

返回一个对象且这个对象包含一个_stopAndResponse等于true的属性,Fizz会终止后续的操作并把这个对象返回给调用方。

# 重定向

通过脚本可以实现重定向,脚本返回一个对象且这个对象同时包含_stopAndResponse=true和_redirectUrl属性,_redirectUrl的值为重定向的目标URL,Fizz会终止后续的操作并进行重定向。JavaScript脚本样例如下:

# 配置路由

至此服务编排的接口配置完成,但此时还不能通过网关访问接口,需要到网关管理-路由管理里配置路由

# 在线测试

  • 支持在线实时测试
  • 支持测试接口和正式接口隔离
  • 支持返回上下文,可以查看整个执行过程中各个步骤及请求的输入与输出
  • 支持保存历史测试记录

支持调试模式,在测试接口和正式接口均可使用,修改后重新发布可实时生效,在调试模式下会打印请求日志及报文,主要用于排查线上问题

# 脚本执行异常

当脚本执行异常时context里会记录异常信息

  • exceptionMessage 异常信息
  • exceptionStacks 异常堆栈信息
  • exceptionData 引起异常的脚本数据
// 上下文数据结构设计
+// 上下文,用于保存客户输入输出和每个步骤的输入与输出结果
+var context = {
+	// 是否DEBUG模式
+	debug:false,
+	
+	// exception info
+	exceptionMessage: "",
+	exceptionStacks: "",
+  exceptionData: "", // such as script source code that cause exception
+
+  // ... other fields
+} 
+

在请求里加上returnContext=true可以返回context上下文,异常信息样例:

# 导入导出

导入导出主要用于在各个环境间同步接口配置,在开发环境配置好后导到测试环境中测试,测试完后导到生产环境进行发布

# 发布|下线和审核

目前发布|下线申请有以上两个入口。

  • 批量发布:对发布单里的接口进行批量发布
  • 批量回滚:对发布单里的接口进行批量回滚
  • 发布:实时发布到网关
  • 回滚:支持回滚到历史任何一个版本,可在发布历史里指定一个版本进行回滚
  • 下线:从网关删除接口,在后台可以通过发布功能再次上线

# 发布流程说明

申请发布、审核、发布和下线功能的权限可根据需要灵活分配给不同角色,如:开发人员只能申请发布,上级领导审核,运维或测试人员执行发布、回滚或下线。在开发、测试和预生产环境为了方便开发人员调试也可把申请发布、审核、发布和下线功能都分配给开发人员。

上次更新: 2020-11-24 18:2
- + diff --git a/docs/guide/aggregate/index.html b/docs/guide/aggregate/index.html index 80176f7..e9faedf 100644 --- a/docs/guide/aggregate/index.html +++ b/docs/guide/aggregate/index.html @@ -7,7 +7,7 @@ - + @@ -23,7 +23,7 @@ 使用文档 查看源码 -

# 什么是服务编排

服务编排主要基于现有的业务微服务使用在线配置的方式快速的生成一个聚合接口。

特点: 在线API设计、在线测试、快速开发

# 举例说明

订单详情页面需要展示订单信息、商品信息和用户信息。可通过配置的方式生成一个接口先后调用底层微服务的订单详情接口、商品信息接口和用户信息接口,再从这3个接口的返回结果里提取需要的字段返回给前端页面。

# 服务编排架构

# 适用场景

# 前端

1、一个页面调用多个接口时,可以编排好返回聚合结果,提高页面数据的加载速度

2、移动设备计算能力有限,可以把数据计算或业务处理逻辑放到服务端完成,加快页面响应

# 后端

1、替换应用层的聚合接口,减少应用层的胶水代码

2、快速生成透传数据类型的接口

3、数据转换和映射

上次更新: 2020-11-9 11:50
- + diff --git a/docs/guide/aggregate/overview.html b/docs/guide/aggregate/overview.html index 27ab75a..ae773bc 100644 --- a/docs/guide/aggregate/overview.html +++ b/docs/guide/aggregate/overview.html @@ -7,7 +7,7 @@ - + @@ -23,7 +23,7 @@ 使用文档 查看源码 -

1.创建服务

此服务是一个分组的概念,可以包含多个聚合接口,类似于微服务体系里的服务

2.创建服务编排接口

3.开通网关白名单和配置访问策略和插件

4.测试服务编排接口

5.发布接口

界面总览

上次更新: 2020-11-9 11:50
- + diff --git a/docs/guide/benchmark/index.html b/docs/guide/benchmark/index.html index f29e88f..fb945bd 100644 --- a/docs/guide/benchmark/index.html +++ b/docs/guide/benchmark/index.html @@ -7,7 +7,7 @@ - + @@ -23,7 +23,7 @@ 使用文档 查看源码 -

# 基准测试结果

我们将Fizz与Spring官方spring-cloud-gateway进行比较,使用相同的环境和条件,测试对象均为单个节点。

产品 QPS 90% Latency(ms)
直接访问后端服务 9087.46 10.76
fizz-gateway 5927.13 19.86
spring-cloud-gateway 5044.04 22.91

# 基准测试详情

# 硬件环境

后端服务所在服务器:

4核8G内存

Intel(R) Xeon(R) CPU X5675 @ 3.07GHz * 4

Linux version 3.10.0-327.el7.x86_64

节点所在服务器:

4核8G内存

Intel(R) Xeon(R) CPU X5675 @ 3.07GHz * 4

Linux version 3.10.0-327.el7.x86_64

压测程序所在服务器:

4核8G内存

Intel(R) Xeon(R) CPU X5675 @ 3.07GHz * 4

Linux version 3.10.0-327.el7.x86_64

# 压测工具

压测软件:wrk

并发连接: 100

# 压测结果截图

- + diff --git a/docs/guide/index.html b/docs/guide/index.html index 2d3f6bd..0d0e63e 100644 --- a/docs/guide/index.html +++ b/docs/guide/index.html @@ -7,7 +7,7 @@ - + @@ -23,7 +23,7 @@ 使用文档 查看源码 -
上次更新: 2020-7-31 17:12
- +
上次更新: 2020-7-31 17:12
+ diff --git a/docs/guide/installation/index.html b/docs/guide/installation/index.html index 564c732..1777c82 100644 --- a/docs/guide/installation/index.html +++ b/docs/guide/installation/index.html @@ -7,7 +7,7 @@ - + @@ -23,7 +23,7 @@ 使用文档 查看源码 -

# 安装依赖

安装以下依赖软件:

  • Redis 2.8或以上版本
  • MySQL 5.7或以上版本
  • Apollo配置中心 (可选)
  • Eureka服务注册中心

# 安装MySQL

  • 操作系统 CentOS 6.5
  • MySQL 5.7.30
  1. 下载MySQL
wget https://downloads.mysql.com/archives/get/p/23/file/mysql-5.7.30-1.el6.x86_64.rpm-bundle.tar
+        

# 安装依赖

安装以下依赖软件:

  • Redis 2.8或以上版本
  • MySQL 5.7或以上版本
  • Apollo配置中心 (可选)
  • Eureka服务注册中心

# 安装MySQL

  • 操作系统 CentOS 6.5
  • MySQL 5.7.30
  1. 下载MySQL
wget https://downloads.mysql.com/archives/get/p/23/file/mysql-5.7.30-1.el6.x86_64.rpm-bundle.tar
 
  1. 解压
tar -xvf mysql-5.7.30-1.el6.x86_64.rpm-bundle.tar
 
  1. 安装
sudo yum install mysql-community-{server,client,common,libs}-*
 
  1. 启动
sudo service mysqld start
@@ -101,6 +101,6 @@ export JAVA_HOME JRE_HOME PATH CLASSPATH
       
       →
     

- + diff --git a/docs/guide/intro/index.html b/docs/guide/intro/index.html index c41e4a9..a9cb36a 100644 --- a/docs/guide/intro/index.html +++ b/docs/guide/intro/index.html @@ -7,7 +7,7 @@ - + @@ -23,11 +23,11 @@ 使用文档 查看源码 -

# 什么是Fizz网关

A Managerment API Gateway in Java . Fizz Gateway 是一个基于 Java开发的微服务网关,能够实现热服务编排、自动授权选择、线上服务脚本编码、在线测试、高性能路由、API审核管理等目的,拥有强大的自定义插件系统可以自行扩展,并且提供友好的图形化配置界面,能够快速帮助企业进行API服务治理、减少中间层胶水代码以及降低编码投入、提高 API 服务的稳定性和安全性。

# Fizz的设计

# 产品特性

  • 集群管理:Fizz网关节点是无状态的,配置信息自动同步,支持节点水平拓展和多集群部署。
  • 服务编排:支持热服务编排能力,支持前后端编码,随时随地更新API。
  • 负载均衡:支持round-robin负载均衡。
  • 服务发现:支持从Eureka注册中心发现后端服务器。
  • 配置中心:支持接入apollo配置中心。
  • HTTP反向代理:隐藏真实后端服务,支持 Rest API反向代理。
  • 访问策略:支持不同策略访问不同的API、配置不同的鉴权等。
  • IP黑白名单:支持配置IP黑白名单。
  • 自定义插件:强大的插件机制支持自由扩展。
  • 可扩展:简单易用的插件机制方便扩展功能。
  • 高性能:性能在众多网关之中表现优异。
  • 版本控制:支持操作的发布和多次回滚。
  • 管理后台:通过管理后台界面对网关集群进行各项配置。
上次更新: 2020-11-9 11:50
- + diff --git a/docs/guide/manager/manager_aggregate.html b/docs/guide/manager/manager_aggregate.html index f6fb035..bb87ed0 100644 --- a/docs/guide/manager/manager_aggregate.html +++ b/docs/guide/manager/manager_aggregate.html @@ -7,7 +7,7 @@ - + @@ -23,7 +23,7 @@ 使用文档 查看源码 -

# 概述

接口列表功能用于维护聚合接口,聚合接口从外部调用方角度看是一个简单的接口,通过入参请求获取响应结果,内部实现会调用多个底层后端服务,将多个调用结果聚合转换成外部调用方想要的数据格式,更多详情请查看服务编排介绍,下面介绍接口列表功能的操作。

# 接口列表

菜单位置:服务编排 > 接口列表。点击菜单后进入接口列表页面,如图所示。

manager_aggregate_list_query

# 新增接口

点击 新增 按钮弹出新增窗口,如图所示。

manager_aggregate_add_1

# 基础信息

manager_aggregate_add_2

所属服务:接口所属服务,更多详情请查看服务管理功能介绍,必选;

接口名:接口名称,用于展示使用,长度不能超过200个字符,必填;

方法:接口请求方法类型,可选GET|POST,必选;

路径:接口请求路径后缀,长度不能超过2000个字符,必填;

开发人员:接口对应负责的开发人员,长度不能超过200个字符;

描述:接口功能描述,长度不能超过2000个字符;

举个例子,所属服务设置my-test-service,方法设置POST,路径设置test-aggregate-post,对应的聚合接口请求为 POST http://{Fizz网关ip地址}:{port端口}/proxy/my-test-service/test-aggregate-post。

# 配置输入

聚合接口的入参大部分是通过JSON Schema来定义的,下面先简单地介绍下JSON Schema。

# JSON Schema介绍

JSON Schema实际上也是JSON数据,用于标注和验证JSON文档,可以类比于XML Schema,当前最新版本2019-09。

作为普通用户,我们并不需要去了解JSON Schema的规范内容,只要能够构建JSON Schema即可。

要理解JSON Schema,首先要理解什么是JSON。JSON是JavaScript Object Notation的缩写,一种简单的数据交换格式。最初JSON是基于JavaScript,广泛的应用于万维网。由于其简洁和清晰的层次结构、易于人阅读等特性,使得越来越多的场景下被采用。

JSON包含以下数据结构:

- + diff --git a/docs/guide/manager/manager_aggregate_approve.html b/docs/guide/manager/manager_aggregate_approve.html index 505745d..9273843 100644 --- a/docs/guide/manager/manager_aggregate_approve.html +++ b/docs/guide/manager/manager_aggregate_approve.html @@ -7,7 +7,7 @@ - + @@ -23,7 +23,7 @@ 使用文档 查看源码 -

# 概述

聚合接口的发布|下线操作需要提交发布|下线申请,审核通过后申请人才能执行发布|下线操作。待审核功能用于审核发布|下线申请,下面介绍待审核功能。

# 审核列表

菜单位置:发布申请 > 待审核。点击菜单后进入审核列表页面,如图所示。

manager_aggregate_approve_list_query

# 审核操作

点击 查看 按钮可以查看发布|下线申请详情,详情页中可执行审核操作。

申请列表页提供快速审核操作,点击 审核 按钮后弹出审核确认窗口,如图所示。

manager_aggregate_approve_op_1

manager_aggregate_approve_op_2

审核结果:勾选通过,审核后申请能可执行申请的操作;勾选不通过,审核后申请失败,申请人不能执行申请的操作。

审核后申请人会收到审核结果邮件通知,如下图是审核通过的邮件通知。

manager_aggregate_approve_op_3

上次更新: 2020-11-9 11:50
- + diff --git a/docs/guide/manager/manager_aggregate_approve_op_log.html b/docs/guide/manager/manager_aggregate_approve_op_log.html index 3ecf34f..4ca11ff 100644 --- a/docs/guide/manager/manager_aggregate_approve_op_log.html +++ b/docs/guide/manager/manager_aggregate_approve_op_log.html @@ -7,7 +7,7 @@ - + @@ -23,7 +23,7 @@ 使用文档 查看源码 -

# 概述

管理后台记录了发布|下线申请的审核操作日志,审核日志功能提供界面查询后台记录的审核操作日志。

# 审核日志列表

菜单位置:发布申请 > 审核日志。点击菜单后进入审核日志列表页面,如图所示。

manager_aggregate_approve_op_log_list_query

# 审核日志详情

点击 查看 按钮弹出审核日志详情页面,如图所示。

manager_aggregate_approve_op_log_detail_1

manager_aggregate_approve_op_log_detail_2

上次更新: 2020-11-9 11:50
- + diff --git a/docs/guide/manager/manager_aggregate_my_apply.html b/docs/guide/manager/manager_aggregate_my_apply.html index 9fe7b7b..79cebfe 100644 --- a/docs/guide/manager/manager_aggregate_my_apply.html +++ b/docs/guide/manager/manager_aggregate_my_apply.html @@ -7,7 +7,7 @@ - + @@ -23,7 +23,7 @@ 使用文档 查看源码 -

# 概述

聚合接口的发布|下线操作需要提交发布|下线申请,审核通过后申请人才能执行发布|下线操作。我的申请功能用于发布|下线申请过程的相关操作,下面介绍我的申请功能。

# 申请列表

菜单位置:发布申请 > 我的申请。点击菜单后进入申请列表页面,如图所示。

manager_aggregate_my_apply_list_query

# 申请撤回

对于已提交但未被审核的申请可执行撤回操作,点击 撤回 按钮弹出确认窗口,如图所示。

manager_aggregate_my_apply_revoke_1

点击 确定 按钮后确认撤回申请,如图所示。

manager_aggregate_my_apply_revoke_2

撤回后审核人会收到邮箱提醒无需再处理该申请,如图所示。

manager_aggregate_my_apply_revoke_3

撤回后可对申请重新进行编辑后再次提交,点击 编辑 按钮后弹出编辑窗口,如图所示。

manager_aggregate_my_apply_revoke_4

点击 确定 按钮后再次提交申请,如图所示。

manager_aggregate_my_apply_revoke_5

# 申请详情

点击 查看 按钮查看申请详情。

manager_aggregate_my_apply_detail_1

manager_aggregate_my_apply_detail_2

操作日志记录该申请的所有操作,包括申请提交、申请撤回、申请重新提交、审核不通过、审核通过、修改审核人、接口发布、接口下线 、接口回滚、接口撤回。

待审核状态申请可以更换审核人,点击 修改审核人 按钮后弹出修改审核人窗口,如图所示。

manager_aggregate_my_apply_detail_3

重新选择审核人后点击 确定 按钮,修改审核人完成。

修改后原审核人会收到邮件提醒无须再处理该申请。

修改后新的审核人会收到邮件提醒需要处理该申请。

审核通过后可以对接口进行发布操作,如图所示。

manager_aggregate_my_apply_detail_4

批量发布:对申请内的接口批量发布推送到Fizz网关。

批量回滚:对申请内的接口批量回滚到上一个版本,当发布后接口异常时该操作相当有用。

对于申请通过后又无须操作的接口可以执行撤回操作,撤回接口时必须填写备注信息用于回溯查询,如图所示。

manager_aggregate_my_apply_detail_5

manager_aggregate_my_apply_detail_6

上次更新: 2020-11-9 11:50
- + diff --git a/docs/guide/manager/manager_aggregate_op_log.html b/docs/guide/manager/manager_aggregate_op_log.html index 73b1cc1..98727e4 100644 --- a/docs/guide/manager/manager_aggregate_op_log.html +++ b/docs/guide/manager/manager_aggregate_op_log.html @@ -7,7 +7,7 @@ - + @@ -23,7 +23,7 @@ 使用文档 查看源码 -

# 概述

管理后台记录了聚合接口的新增、修改、发布、下线、回滚、删除操作日志,通过查看操作日志可以清楚地掌握接口的操作轨迹。操作日志功能提供界面查询聚合接口的操作日志。

# 操作日志列表

菜单位置:服务编排 > 操作日志。点击菜单后进入操作日志列表页面,如图所示。

manager_aggregate_op_log_list_query

# 查看日志详情

点击 查看 按钮弹出操作日志详情页面,如图所示。

manager_aggregate_op_log_detail_1

manager_aggregate_op_log_detail_2

上次更新: 2020-11-9 11:50
- + diff --git a/docs/guide/manager/manager_api_auth.html b/docs/guide/manager/manager_api_auth.html index 3d8e4f2..ba318bf 100644 --- a/docs/guide/manager/manager_api_auth.html +++ b/docs/guide/manager/manager_api_auth.html @@ -7,7 +7,7 @@ - + @@ -23,7 +23,7 @@ 使用文档 查看源码 -

# 概述

路由管理功能用于维护网关的路由规则,支持按请求路径转发、转发到指定后端服务两种转发规则,支持插件配置。下面介绍路由管理的操作。

# 路由列表

菜单位置:网关管理 > 路由管理。点击菜单后进入路由列表页面,如图所示。

manager_api_auth_list_query

# 新增路由

点击 新增 按钮弹出新增窗口,如图所示。

manager_api_auth_add_1

manager_api_auth_add_2

网关分组:选取路由关联的网关分组,只有属于所选分组的网关实例路由规则才会生效,必选;

服务:网关的请求路径格式为 http://{ip}:{port}/proxy/{service}{apiPath},服务对应{service}段,当 转发 选择 按请求路径转发 时服务需要是聚合配置的服务或者是Eureka注册的服务,当 转发 选择 转发到指定后端服务 时服务不需要是实际存在的服务,只用于路径匹配使用,长度不能超过50个字符,必填;

API方法:请求的method类型,可选GET|POST;

API Path:网关的请求路径格式为 http://{ip}:{port}/proxy/{service}{apiPath},API Path对应{apiPath}段,使用前缀匹配原则,例如"/api/"将匹配"/api/"、"/api/1"、"/api/1/1"等路径;

应用:选取路由关联的应用,网关使用选取应用的信息进行鉴权,更多详情请查看appID管理功能介绍;

访问:可选允许|禁止,必选;

转发:可选按请求路径转发|转发到指定后端服务,当选择 按请求路径转发 时,请求会按请求路径转发,例如网关请求 http://{ip}:{port}/proxy/my-service/api-path 将转发到 http://my-service/api-path;当选择 转发到指定后端服务 时,需要添加转发到的后端服务URL,请求会转发到配置的后端服务,例如配置了服务为 my-service,API Path为空,后端服务URL为 http://127.0.0.1:8080/forward-service/,网关请求 http://{ip}:{port}/proxy/my-service/api-path 将转发到 http://127.0.0.1:8080/forward-service/api-path。

点击 添加插件 按钮为路由添加插件,如图所示。

manager_api_auth_add_3

配置插件路由级别的自定义配置,表单界面来自于插件的表单定义,更多详情请查看插件管理功能介绍。

manager_api_auth_add_4

配置完成后点击 保存 按钮保存路由规则。

manager_api_auth_add_5

# 编辑路由

点击 编辑 按钮弹出编辑窗口,如图所示。

manager_api_auth_edit_1

manager_api_auth_edit_2

# 删除路由

点击 删除 按钮弹出删除确认窗口,如图所示。

manager_api_auth_delete_1

manager_api_auth_delete_2

上次更新: 2020-11-9 11:50
- + diff --git a/docs/guide/manager/manager_app_id.html b/docs/guide/manager/manager_app_id.html index 4757b96..419f4bb 100644 --- a/docs/guide/manager/manager_app_id.html +++ b/docs/guide/manager/manager_app_id.html @@ -7,7 +7,7 @@ - + @@ -23,7 +23,7 @@ 使用文档 查看源码 -

# 概述

appID管理功能维护应用鉴权信息,可配置是否启用签名、是否启用IP白名单,AppID级别的自定义配置供自定义插件使用。appID用于在路由管理配置中关联路由规则,当对应路由规则触发时会对应用进行鉴权。

# appID列表

菜单位置:网关管理 > appID管理。点击菜单后进入appID列表页面,如图所示。

manager_app_id_list_query

# 新增appID

点击 新增 按钮弹出新增窗口,如图所示。

manager_app_id_add_1

manager_app_id_add_2

appID:第三方应用唯一标识,长度不能超过64个字符,必填;

应用名:第三方应用名称,长度不能超过128个字符,必填;

是否启用签名:当启动时必须配置 认证方式 和 密钥;

认证方式:可选 密钥(使用网关内置鉴权方式验证)|自定义认证插件(使用自定义的鉴权逻辑),更多信息请查看Fizz网关的介绍;启用签名时必填;

密钥:第三方应用使用的密钥,可通过 生成随机密钥 按钮生成一个随机的密钥,启用签名时必填;

是否启用IP白名单:当启用时可以配置 IP白名单,网关会根据请求来源IP地址进行过滤;

IP白名单:IP段支持 1.2.3.100-120 和 1.2.3.*两种格式,仅最后一段可用范围或星号表示;

自定义配置:AppID级别的自定义配置供自定义插件使用,所有插件均可获取到此配置信息。

# 编辑appID

点击 编辑 按钮弹出编辑窗口,如图所示。

manager_app_id_edit_1

manager_app_id_edit_2

# 删除appID

点击 删除 按钮弹出删除确认窗口,如图所示。

manager_app_id_delete_1

manager_app_id_delete_2

点击 确定 按钮后删除appID,如果appID存在关联的路由配置时,对应关联的路由配置也会一起删除。

上次更新: 2020-11-9 11:50
- + diff --git a/docs/guide/manager/manager_gateway_aggregate_cache.html b/docs/guide/manager/manager_gateway_aggregate_cache.html index 81e5c0d..4db5ede 100644 --- a/docs/guide/manager/manager_gateway_aggregate_cache.html +++ b/docs/guide/manager/manager_gateway_aggregate_cache.html @@ -7,7 +7,7 @@ - + @@ -23,7 +23,7 @@ 使用文档 查看源码 -

# 概述

网关缓存功能用于查询Fizz网关实例本地缓存的已发布接口信息,可以快速的了解当前网关实例生效的全部接口,同时通过查看后台接口发布版本号与网关实例本地缓存的接口版本号是否一致可以排查接口缓存问题,下面介绍网关缓存功能的操作。

# 网关列表

菜单位置:服务编排 > 网关缓存。点击菜单后进入网关列表页面,如图所示。

manager_aggregate_gateway_list_query

Fizz网关与后台注册到同一个eureka注册中心,后台通过eureka获取网关的实例列表。

# 网关缓存列表

点击 查看 按钮后弹出网关详情页面,该页面显示所选网关实例的接口缓存列表,如图所示。

manager_aggregate_gateway_cache_list_query_1

manager_aggregate_gateway_cache_list_query_2

# 网关缓存详情

点击 查看 按钮弹出所选接口的配置详情,如图所示。

manager_aggregate_gateway_cache_detail_1

manager_aggregate_gateway_cache_detail_2

上次更新: 2020-11-9 11:50
- + diff --git a/docs/guide/manager/manager_gateway_group.html b/docs/guide/manager/manager_gateway_group.html index 019efcf..01ef51f 100644 --- a/docs/guide/manager/manager_gateway_group.html +++ b/docs/guide/manager/manager_gateway_group.html @@ -7,7 +7,7 @@ - + @@ -23,7 +23,7 @@ 使用文档 查看源码 -

# 概述

网关分组功能用于维护分组元数据,将网关实例IP与分组关联,通过为不同的分组配置不同的路由策略,从而实现网关的分组管理。

# 分组示例

我们的线上业务涉及To C(个人用户)、To B(企业)、To T(第三方),对于不同业务会有对应的机器接受请求访问,不同的业务需要有各自的路由策略,因此进行了如下的分组划分。

分组ID 分组名称 描述
default 默认分组 默认分组是后台默认创建的分组,不用指定IP,不属于其它分组的机器都归到默认分组,默认分组不可修改或删除
c 2c分组 只接受面向个人用户的请求
b 2b分组 只接受面向企业的请求
t 面向第三方的分组 只接受面向第三方的请求

下面介绍网关分组功能的操作。

# 分组列表

菜单位置:网关管理 > 网关分组。点击菜单后进入分组列表页面,如图所示。

manager_gateway_group_list_query

# 新增分组

点击 新增 按钮弹出新增窗口,如图所示。

manager_gateway_group_add_1

manager_gateway_group_add_2

分组ID:分组的唯一标识,长度不能超过32个字符,必填;

分组名称:分组的名称,用于在分组选项时展示,长度不能超过32个字符,必填;

网关实例IP:Fizz网关集群内的机器IP地址,多个IP地址使用逗号分隔。

# 编辑分组

点击 编辑 按钮弹出编辑窗口,如图所示。

manager_gateway_group_edit_1

manager_gateway_group_edit_2

# 删除分组

点击 删除 按钮弹出删除确认窗口,如图所示。

manager_gateway_group_delete_1

manager_gateway_group_delete_2

点击 确定 按钮后删除网关分组,如果网关分组存在关联的路由配置时,需要将关联的路由配置全部删除后才能删除分组。

上次更新: 2020-11-9 11:50
- + diff --git a/docs/guide/manager/manager_overview.html b/docs/guide/manager/manager_overview.html index 4e42828..840997b 100644 --- a/docs/guide/manager/manager_overview.html +++ b/docs/guide/manager/manager_overview.html @@ -7,7 +7,7 @@ - + @@ -23,7 +23,7 @@ 使用文档 查看源码 -

# 概述

Fizz管理后台是Fizz网关的配套系统,基于Java、Vue开发,通过界面对Fizz网关集群进行各项配置。

# 功能

Fizz管理后台包含如下功能:

- + diff --git a/docs/guide/manager/manager_plugin.html b/docs/guide/manager/manager_plugin.html index f3a9537..e65b353 100644 --- a/docs/guide/manager/manager_plugin.html +++ b/docs/guide/manager/manager_plugin.html @@ -7,7 +7,7 @@ - + @@ -23,7 +23,7 @@ 使用文档 查看源码 -

# 概述

插件管理功能用于维护插件元数据,定义路由级别的自定义属性、插件级别的自定义配置信息。创建的插件用于路由管理设置时启用,当网关接受请求匹配路由规则时会触发启用的插件逻辑执行,插件逻辑中可获取到自定义的属性数据。

# 插件列表

菜单位置:网关管理 > 插件管理。点击菜单后进入插件管理列表页面,如图所示。

manager_plugin_list_query

# 新增插件

点击 新增 按钮弹出新增窗口,如图所示。

manager_plugin_add_1

manager_plugin_add_2

插件名称:插件名称由英文字母、下划线或数字组成,不能以数字开头,长度不能超过50个字符,必填;

插件描述:插件的简要描述,长度不能超过50个字符,必填;

默认执行顺序:插件的默认执行顺序,按从小到大排序,值越小越先执行,取值范围0~255,必填;

表单定义:路由级别的自定义属性,在路由管理配置启用插件时前端会将表单定义转化为表单输入界面,更多信息请查看路由管理介绍。表单规范说明如下:

/*
+        

# 概述

插件管理功能用于维护插件元数据,定义路由级别的自定义属性、插件级别的自定义配置信息。创建的插件用于路由管理设置时启用,当网关接受请求匹配路由规则时会触发启用的插件逻辑执行,插件逻辑中可获取到自定义的属性数据。

# 插件列表

菜单位置:网关管理 > 插件管理。点击菜单后进入插件管理列表页面,如图所示。

manager_plugin_list_query

# 新增插件

点击 新增 按钮弹出新增窗口,如图所示。

manager_plugin_add_1

manager_plugin_add_2

插件名称:插件名称由英文字母、下划线或数字组成,不能以数字开头,长度不能超过50个字符,必填;

插件描述:插件的简要描述,长度不能超过50个字符,必填;

默认执行顺序:插件的默认执行顺序,按从小到大排序,值越小越先执行,取值范围0~255,必填;

表单定义:路由级别的自定义属性,在路由管理配置启用插件时前端会将表单定义转化为表单输入界面,更多信息请查看路由管理介绍。表单规范说明如下:

/*
 * plugin_config_design
 * 动态插件参考结构
 * */
@@ -143,6 +143,6 @@
       
       →
     

- + diff --git a/docs/guide/manager/manager_role.html b/docs/guide/manager/manager_role.html index c5c08dc..551a3af 100644 --- a/docs/guide/manager/manager_role.html +++ b/docs/guide/manager/manager_role.html @@ -7,7 +7,7 @@ - + @@ -23,7 +23,7 @@ 使用文档 查看源码 -

# 概述

角色管理功能维护角色元数据,通过配置角色拥有的菜单资源,限制用户只能操作拥有的角色对应的菜单资源,下面介绍角色管理功能的操作。

# 角色列表

菜单位置:权限管理 > 角色管理。点击菜单后进入角色列表页面,如图所示。

manager_role_list_query

# 添加角色

点击 新增 按钮弹出新增窗口,如图所示。

manager_role_add_1

manager_role_add_2

# 权限设置

勾选需要分配权限的角色,点击 权限设置 按钮弹出角色权限配置窗口,如图所示。

manager_role_auth_1

manager_role_auth_2

勾选菜单后点击 确定 按钮确认给角色分配菜单权限。

# 编辑角色

点击 编辑 按钮弹出编辑窗口,如图所示。

manager_role_edit_1

manager_role_edit_2

# 删除角色

点击 删除 按钮弹出删除确认窗口,如图所示。

manager_role_delete_1

manager_role_delete_2

点击 确定 按钮后删除角色。

上次更新: 2020-11-9 11:50
- + diff --git a/docs/guide/manager/manager_service.html b/docs/guide/manager/manager_service.html index 4d46ce9..5c17454 100644 --- a/docs/guide/manager/manager_service.html +++ b/docs/guide/manager/manager_service.html @@ -7,7 +7,7 @@ - + @@ -23,7 +23,7 @@ 使用文档 查看源码 -

# 概述

服务管理功能维护服务元数据。服务编排中的服务是一个逻辑上的概念,用于对聚合接口的归类以及权限的分配。Fizz网关聚合接口的请求路径格式为 http://{ip}:{port}/proxy/{service}{apiPath},服务对应{service}段。

# 服务列表

菜单位置:服务编排 > 服务管理。点击菜单后进入服务列表页面,如图所示。

manager_service_list_query

# 新增服务

点击 新增 按钮弹出新增窗口,如图所示。

manager_service_add_1

manager_service_add_2

服务 ID:服务唯一标识,对应Fizz网关聚合接口请求路径(格式为 http://{ip}:{port}/proxy/{service}{apiPath})的{service}段,长度不能超过200个字符,必填;

服务名:服务名称,用于展示或者选项使用,必填;

团队:团队名称,长度不能超过200个字符;

负责人:负责人名称,长度不能超过200个字符;

描述:服务描述,长度不能超过2000个字符。

# 编辑服务

点击 编辑 按钮弹出编辑窗口,如图所示。

manager_service_edit_1

manager_service_edit_2

# 删除服务

点击 删除 按钮弹出删除确认窗口,如图所示。

manager_service_delete_1

manager_service_delete_2

点击 确定 按钮后删除服务,如果服务存在关联的聚合接口时,需要将关联的聚合接口全部删除后才能删除服务。

# 服务权限分配

点击 权限 按钮弹出权限配置窗口,如图所示。

manager_service_auth_1

manager_service_auth_2

服务创建人自动获得服务权限,服务权限可分配,拥有权限的用户才能操作对应的接口列表。

上次更新: 2020-11-9 11:50
- + diff --git a/docs/guide/manager/manager_source_statistics.html b/docs/guide/manager/manager_source_statistics.html index cf3f669..343bf36 100644 --- a/docs/guide/manager/manager_source_statistics.html +++ b/docs/guide/manager/manager_source_statistics.html @@ -7,7 +7,7 @@ - + @@ -23,7 +23,7 @@ 使用文档 查看源码 -

# 概述

Fizz网关会将访问请求数据(IP地址、网关分组、服务、应用、请求方法、API Path、请求时间)推送到Kafka中,管理后台消费Kafka消息统计接口访问数据。

接口统计功能以图表的形式展示指定时间段内每日的接口总数、访问次数,可查看接口的历史访问总次数以及最近请求时间。

# 接口访问统计

菜单位置:网关管理 > 接口统计。点击菜单后进入接口统计页面,如图所示。

manager_source_statistics_1.png

今天接口总数:从0时到当前时刻被调用不同接口的总数;

今天访问次数:从0时到当前时刻访问请求的总次数。

接口总数图表:显示指定时间段内每日被调用不同接口的总数曲线;

访问次数图表:显示指定时间段内每日访问请求的总次数曲线。

# 请求统计

接口统计界面下部为请求统计列表,如图所示。

manager_source_statistics_2.png

来源IP:网关请求的实际入口IP地址;

请求次数:( 唯一[来源IP、网关分组、服务名、请求方法、appID、API Path])历史总请求次数;

最近请求时间:( 唯一[来源IP、网关分组、服务名、请求方法、appID、API Path])最近一次调用时间。

上次更新: 2020-11-9 11:50
- +

# 概述

Fizz网关会将访问请求数据(IP地址、网关分组、服务、应用、请求方法、API Path、请求时间)推送到Kafka中,管理后台消费Kafka消息统计接口访问数据。

接口统计功能以图表的形式展示指定时间段内每日的接口总数、访问次数,可查看接口的历史访问总次数以及最近请求时间。

# 接口访问统计

菜单位置:网关管理 > 接口统计。点击菜单后进入接口统计页面,如图所示。

manager_source_statistics_1.png

今天接口总数:从0时到当前时刻被调用不同接口的总数;

今天访问次数:从0时到当前时刻访问请求的总次数。

接口总数图表:显示指定时间段内每日被调用不同接口的总数曲线;

访问次数图表:显示指定时间段内每日访问请求的总次数曲线。

# 请求统计

接口统计界面下部为请求统计列表,如图所示。

manager_source_statistics_2.png

来源IP:网关请求的实际入口IP地址;

请求次数:( 唯一[来源IP、网关分组、服务名、请求方法、appID、API Path])历史总请求次数;

最近请求时间:( 唯一[来源IP、网关分组、服务名、请求方法、appID、API Path])最近一次调用时间。

上次更新: 2020-11-9 11:50
+ diff --git a/docs/guide/manager/manager_user.html b/docs/guide/manager/manager_user.html index d83a3b0..2631179 100644 --- a/docs/guide/manager/manager_user.html +++ b/docs/guide/manager/manager_user.html @@ -7,7 +7,7 @@ - + @@ -23,11 +23,15 @@ 使用文档 查看源码 -

# 概述

用户管理功能用于维护用户元数据,包括用户信息维护、密码维护、角色配置。

# 用户列表

菜单位置:系统管理 > 用户管理。点击菜单后进入用户列表页面,如图所示。

manager_user_list_query

# 添加用户

点击 新增 按钮弹出新增窗口,如图所示。

manager_user_add_1

manager_user_add_2

电子邮箱:用户用于接收电子邮件的邮箱地址,后台涉及邮件发送业务使用该字段设置的邮箱地址来进行邮箱发送。

# 重置密码

勾选用户后点击 密码重置 按钮可为用户重置密码。

manager_user_reset_password_1

manager_user_reset_password_2

重置后的默认密码为AsdF1234!

# 编辑用户

点击 编辑 按钮弹出编辑窗口,如图所示。

manager_user_edit_1

manager_user_edit_2

# 删除用户

点击 删除 按钮弹出删除确认窗口,如图所示。

manager_user_delete_1

manager_user_delete_2

上次更新: 2020-11-9 11:50
- + + Roadmap + + → +

+ diff --git a/docs/guide/plugin/index.html b/docs/guide/plugin/index.html index 002d9ca..3fe4b6a 100644 --- a/docs/guide/plugin/index.html +++ b/docs/guide/plugin/index.html @@ -7,7 +7,7 @@ - + @@ -23,7 +23,7 @@ 使用文档 查看源码 -

# 概述

当需要在gateway中加入自定义的逻辑时,可通过fizz的插件机制实现,插件:
+

# 概述

当需要在gateway中加入自定义的逻辑时,可通过fizz的插件机制实现,插件:
1、类似spring的WebFilter,是fizz内部的WebFilter,由fizz调度;
2、对不同的请求,可配置不同的上下文参数,可通过manager完成配置;
3、若有多个插件,当前插件可获取前面插件的执行结果。

插件的开发和应用,分gateway开发、manager配置两部分,下面以一个例子,依次介绍。

# gateway开发

    实现
@@ -120,6 +120,6 @@
       
       →
     

- + diff --git a/docs/guide/proxy/index.html b/docs/guide/proxy/index.html index 1da1112..0035642 100644 --- a/docs/guide/proxy/index.html +++ b/docs/guide/proxy/index.html @@ -7,7 +7,7 @@ - + @@ -23,7 +23,7 @@ 使用文档 查看源码 -

# 路由转发介绍

路由转发也叫反向代理,为内部微服务提供统一的对外入口。支持以下功能:

  • 支持服务注册与发现
  • 支持负载均衡
  • 支持黑白名单机制
  • 支持配置插件

# 接入路由转发

  • 前提条件:接入Eureka注册中心
  • 开通白名单,接入注册中心的服务默认不对公网开放 (白名单在配置文件里配置serviceWhiteList)
  • 配置访问权限 (管理后台-接口代理-API查询)
上次更新: 2020-9-8 15:3
- + diff --git a/docs/guide/roadmap/index.html b/docs/guide/roadmap/index.html new file mode 100644 index 0000000..371e8e8 --- /dev/null +++ b/docs/guide/roadmap/index.html @@ -0,0 +1,33 @@ + + + + + + Roadmap | Fizz Gateway + + + + + + + +

# v1.2.x

  • 支持Nacos注册中心和配置中心
  • 输出服务编排脚本异常信息
  • 支持在服务编排里配置重定向
  • 增加内置的默认common.js
  • 支持接口统计

# v1.3.x

  • 支持接口回调
  • 优先路由配置
  • 支持后台查看日志
  • 优化单机部署

# v1.4.x

  • 支持流控管理(限流,降级,流速等)
  • 支持内容模块插件化
  • 支持动态添加插件
  • 支持使用正则匹配路由

# v1.5.x

  • 支持Docker容器部署
  • 支持MySQL input
  • 发布审核功能使用工作流

# v1.6.x

  • 支持Dubbo
上次更新: 2020-11-24 17:59
+ + + diff --git a/docs/index.html b/docs/index.html index 173a2d3..ac9e6ca 100644 --- a/docs/index.html +++ b/docs/index.html @@ -7,7 +7,7 @@ - + @@ -32,6 +32,6 @@

智能路由

支持服务注册与发现,支持负载均衡,支持配置插件和黑白名单。

服务编排

基于现有的业务微服务通过在线配置的方式快速的生成一个聚合接口。减少中间层胶水代码以及降低编码投入

插件机制

强大的插件系统,内置通用常用插件,同时支持自定义插件开发。

- + From f3eb94a0ec8274af7f3a1293ee0d2e764030c631 Mon Sep 17 00:00:00 2001 From: zhongjie Date: Tue, 24 Nov 2020 18:42:35 +0800 Subject: [PATCH 13/14] 1.add subscribe for access stat channel to really send data 2.set stat.open true to open push access stat data --- src/main/java/we/plugin/stat/StatPluginFilter.java | 2 +- src/main/resources/application.yml | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/java/we/plugin/stat/StatPluginFilter.java b/src/main/java/we/plugin/stat/StatPluginFilter.java index 8eb25d6..c682faf 100644 --- a/src/main/java/we/plugin/stat/StatPluginFilter.java +++ b/src/main/java/we/plugin/stat/StatPluginFilter.java @@ -112,7 +112,7 @@ public class StatPluginFilter extends PluginFilter { b.append(Constants.Symbol.RIGHT_BRACE); if (StringUtils.isBlank(fizzAccessStatTopic)) { - rt.convertAndSend(fizzAccessStatChannel, b.toString()); + rt.convertAndSend(fizzAccessStatChannel, b.toString()).subscribe(); } else { log.info(b.toString(), LogService.HANDLE_STGY, LogService.toKF(fizzAccessStatTopic)); } diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 9ecca22..f9a03bc 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -78,4 +78,8 @@ aggr-webclient: fizz-web-client: timeout: 20000 log: - headers: COOKIE,FIZZ-APPID,FIZZ-SECRETKEY,FIZZ-SIGN,FIZZ-TS,FIZZ-RSV \ No newline at end of file + headers: COOKIE,FIZZ-APPID,FIZZ-SECRETKEY,FIZZ-SIGN,FIZZ-TS,FIZZ-RSV + +stat: + # switch for push access stat data + open: true \ No newline at end of file From 51e0bbe7d38c703011d5bdb2ca2e0f0dcdfa961b Mon Sep 17 00:00:00 2001 From: dxfeng10 Date: Wed, 25 Nov 2020 10:46:49 +0800 Subject: [PATCH 14/14] Create CNAME --- docs/CNAME | 1 + 1 file changed, 1 insertion(+) create mode 100644 docs/CNAME diff --git a/docs/CNAME b/docs/CNAME new file mode 100644 index 0000000..f93aefc --- /dev/null +++ b/docs/CNAME @@ -0,0 +1 @@ +www.fizzgate.com \ No newline at end of file