introduce
The Soul Gateway uses the Redirect plug-in to redirect requests when making proxy calls to target services. There are two scenarios: One is to configure redirectUrl as a third-party URL address and directly use 308 for forwarding; the other is to forward the redirectUrl configuration starting with/to the gateway itself.
The plug-in configuration
- in
soul-admin
– > Plug-in Management – >redirect
, set it to enable. - in
soul-bootstrap
The projectpom.xml
Add to fileredirect
的maven
Rely on. - in
soul- admin
Set the selector rule in the background. Only matching requests will be forwarded and redirected.Selector rule.
Maven rely on
Add the plug-in dependencies to the pom.xml file of the soul-Bootstrap project.
<dependency>
<groupId>org.dromara</groupId>
<artifactId>soul-spring-boot-starter-plugin-redirect</artifactId>
<version>${last.version}</version>
</dependency>
Copy the code
scenario
As the name implies, the Redirect plug-in is simply a redirection and redirection of URIs.
redirect
- We are in
Rule
When you configure a custom path, it should be an accessible service path. - When the request is matched, based on the custom path,
Soul gateway
Will be carried out in308
Service jump.
The interface of the gateway forwards the packet
- If the matching rule is met, the service is used internally
DispatcherHandler
Internal interface forwarding. - To implement interface forwarding of the gateway itself, we need to use it in the configuration path
/
Start as a prefix, as shown in the following figure.
The source code parsing
Soul Gateway is based on SpringBoot WebFlux implementation. If WebFlux is not configured at all by default, it is not configured at all. The request is handled by DispatcherHandler by default. This is the core of reactive MVC processing. We can look at initialization:
protected void initStrategies(ApplicationContext context) { Map<String, HandlerMapping> mappingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false); ArrayList<HandlerMapping> mappings = new ArrayList(mappingBeans.values()); AnnotationAwareOrderComparator.sort(mappings); / / handlerMapping related this. HandlerMappings = Collections. UnmodifiableList (the mappings); Map<String, HandlerAdapter> adapterBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false); HandlerAdapters = new ArrayList(adapterBeans.values()); // AdapterBeans.adapters = new ArrayList(adapterBeans.values()); AnnotationAwareOrderComparator.sort(this.handlerAdapters); Map<String, HandlerResultHandler> beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerResultHandler.class, true, false); // resultHandler correlation this.resulthAndlers = new ArrayList(beans.values()); // resultHandler correlation this.resulthAndlers = new ArrayList(beans.values()); AnnotationAwareOrderComparator.sort(this.resultHandlers); }Copy the code
Then there’s the familiar MVC core that handles the DispatcherHandler#handle method
public Mono<Void> handle(ServerWebExchange exchange) {
return this.handlerMappings == null ? this.createNotFoundError() : Flux.fromIterable(this.handlerMappings).concatMap((mapping) -> {
return mapping.getHandler(exchange);
}).next().switchIfEmpty(this.createNotFoundError()).flatMap((handler) -> {
return this.invokeHandler(exchange, handler);
}).flatMap((result) -> {
return this.handleResult(exchange, result);
});
}
Copy the code
Soul Gateway, SoulWebHandler implements the WebHandler interface, BeanName is declared webHandler instead of registering DispatcherHandler as the default handler.
@Bean("webHandler")
public SoulWebHandler soulWebHandler(final ObjectProvider<List<SoulPlugin>> plugins) {
List<SoulPlugin> pluginList = plugins.getIfAvailable(Collections::emptyList);
List<SoulPlugin> soulPlugins = pluginList.stream()
.sorted(Comparator.comparingInt(SoulPlugin::getOrder)).collect(Collectors.toList());
soulPlugins.forEach(soulPlugin -> log.info("load plugin:[{}] [{}]", soulPlugin.named(), soulPlugin.getClass().getName()));
return new SoulWebHandler(soulPlugins);
}
Copy the code
So far we know that the default request is handled by SoulWebHandler#handle. What if we need to forward it to the gateway’s own MVC? RedirectPlugin is initialized with DispatcherHandler and then distributed by DispatcherHandler according to the specific request. The specific core code is as follows:
@Override protected Mono<Void> doExecute(final ServerWebExchange exchange, final SoulPluginChain chain, final SelectorData selector, final RuleData rule) { final String handle = rule.getHandle(); final RedirectHandle redirectHandle = GsonUtils.getInstance().fromJson(handle, RedirectHandle.class); if (Objects.isNull(redirectHandle) || StringUtils.isBlank(redirectHandle.getRedirectURI())) { log.error("uri redirect rule can not configuration: {}", handle); return chain.execute(exchange); } / / processing begin with/itself forward the if (redirectHandle. GetRedirectURI (). The startsWith (ROOT_PATH_PREFIX)) {ServerHttpRequest request = exchange.getRequest().mutate() .uri(Objects.requireNonNull(UriUtils.createUri(redirectHandle.getRedirectURI()))).build(); ServerWebExchange mutated = exchange.mutate().request(request).build(); return dispatcherHandler.handle(mutated); } else {// if not, return to ServerHttpResponse response = exchange.getresponse (); response.setStatusCode(HttpStatus.PERMANENT_REDIRECT); response.getHeaders().add(HttpHeaders.LOCATION, redirectHandle.getRedirectURI()); return response.setComplete(); }}Copy the code
Reference links:
- Design and working principle analysis of Spring WebFlux
- How Spring WebFlux works
This article uses the article synchronization assistant to synchronize