Spring-Cloud系列文章之Spring-Cloud-GateWay应用总结

今天我们来学习一下SpringCloud中的GateWay,其实看到概念我想大家已经非常了解他的功能了,网关,举个例子,Nginx,我想大家都知道,也知道他是做什么的,使用场景是啥。没错就是网络,主要起到代理,过滤,权限控制,跨域等所有需要访问真正服务之前需要处理的都在网关中进行。我们今天先不拿Nginx来对比,我们来对比一下之前的Zuul然后说说为什么不使用Zuul而需要转向GateWay,因为Zuul是基于servlet,servlet的线程模型大家都清楚,就BIO,就是每个请求一个线程,这种模型的最大弊端就是不能很好的支持大并发,而在Spring5之后,Spring推出了WebFlux基于Reactive线程模型的异步非阻塞框架,服务通过底层的Netty来进行发布及运行,异步非阻塞可以有效降低系统的线程数量,只需要很少的线程就可以完成较高的并发支持,但对于我们习惯了阻塞式编程方式后,我们要逐步改变这种思想,阻塞式编程最直接的就是我要做什么比如IO操作,我就要阻塞当前线程,让当前线程等待我想干的事,等我干完了你再干,虽然说是比较直接,但是并不是很理想,因为没有充分利用少量的资源去做充分的事。异步非阻塞,类似于Nodejs的事件回调,可有效提高系统的并发能力,好处不言而喻。我们说的同步异步都是针对服务器说的,客户端或者用户是感觉不出来的,他们能感觉的就是系统的相应效率。而且异步不一定执行时间就比通不时间短,因为异步是需要很多后续操作的,他只是平衡了一下时间和空间,找到了一个更优的,当下最好的解决方案,所以大家也应该明白了我们为什么选择GateWay了,因为GataWay依赖WebFlux而不依赖servlet所以性能比Zuul要好很多且对高并发有较好的实现。

接下来我们说说GateWay的具体原理,讲完原理性知识,我们在通过代码来总结一些实例,达到快速理解的目的,我们SpringCloud微服务都是将服务注册到服务注册中心,Spring中就是SpringEureka,为了高可用我们会大奖Eureka的集群,之后我们服务都已经注册上了,现在我们需要将服务发布出去,但是直接发布,服务的安全性又没有了保证,所以我们需要一层屏障来对服务进行代理,你可能会说我们做单点登录就可以了啊,可以是可以,当微服务数量比较少的时候还可以,当服务数量较多的时候,单点服务器的认证压力,每个服务的横向扩展又成了瓶颈,所以我们要尽可能的减少可能出现的瓶颈,尽可能保证系统的稳定可靠性,所以我们还是使用网关效果最好。网关我们主要使用的功能主要有两个方面,分别是路由和请求过滤。默认情况下,GateWay的路由策略是

http://gateway_ip:gateway_port/serviceName[全大写]/**

是不是感觉全大写很不爽,没问题他也有转换小写的配置项,下面我们把开启路由和配置小写的配置拿出来。

spring.cloud.gateway.discovery.locator.enabled=true
spring.cloud.gateway.discovery.locator.lowerCaseServiceId=true

现在你运行程序应该已经可以代理到你想访问到的应用了,现在我们想要做一些配置,比如校验必须有token才能访问,没有压根都不处理,还有我们现在要做跨域访问,需要做跨域。

import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.config.EnableWebFlux;

@Configuration
@EnableWebFlux
@ComponentScan(basePackages = "com.easy.cloud")
public class GateWayConfig {
	@Bean
	public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
		return builder.routes().route(t -> t.path("/appA/**").and().uri("http://localhost:8011")).build();
	}
}
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.cors.reactive.CorsUtils;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;

import reactor.core.publisher.Mono;

@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class CorsFilter implements WebFilter {

	@Override
	public Mono<Void> filter(ServerWebExchange swe, WebFilterChain filterChain) {
		ServerHttpRequest request = swe.getRequest();
		if (CorsUtils.isCorsRequest(request)) {
			ServerHttpResponse response = swe.getResponse();
			HttpHeaders headers = response.getHeaders();
			headers.add("Access-Control-Allow-Origin", "*");
			headers.add("Access-Control-Allow-Methods", "*");
			headers.add("Access-Control-Max-Age", "3600");
			headers.add("Access-Control-Allow-Headers", "*");
			headers.add("Access-Control-Allow-Credentials", "true");
		}
		return filterChain.filter(swe);
	}

}
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.core.Ordered;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;

import reactor.core.publisher.Mono;

@Component
public class TokenFilter implements GatewayFilter, Ordered {
	private static final String AUTHORIZE_TOKEN = "token";
	private static final String AUTHORIZE_UID = "uid";

	@Override
	public int getOrder() {
		return 1;
	}

	@Override
	public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
		ServerHttpRequest request = exchange.getRequest();
		HttpHeaders headers = request.getHeaders();
		String token = headers.getFirst(AUTHORIZE_TOKEN);
		String uid = headers.getFirst(AUTHORIZE_UID);
		if (token == null) {
			token = request.getQueryParams().getFirst(AUTHORIZE_TOKEN);
		}
		if (uid == null) {
			uid = request.getQueryParams().getFirst(AUTHORIZE_UID);
		}

		ServerHttpResponse response = exchange.getResponse();
		if (StringUtils.isEmpty(token) || StringUtils.isEmpty(uid)) {
			response.setStatusCode(HttpStatus.UNAUTHORIZED);
			return response.setComplete();
		}
		// String authToken = redisTemplate.opsForValue().get(uid);
		String authToken = "uid1001";
		if (authToken == null || !authToken.equals(token)) {
			response.setStatusCode(HttpStatus.UNAUTHORIZED);
			return response.setComplete();
		}

		return chain.filter(exchange);
	}

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值