API网关是一个更为智能的应用服务器,它有点类似于我们微服务架构系统的门面,所有的外部访问都要先经过API网关,然后API网关来实现请求路由、负载均衡、权限验证等功能。
Spring Cloud中提供的Spring Cloud Zuul实现了API网关的功能。
构建网关
网关的构建我们通过下面三个步骤来实现。
1.创建cloud-gateway工程,并添加依赖。
pom.xml文件 主要内容如下:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.3.RELEASE</version>
<relativePath />
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zuul</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Brixton.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement></project>
说明:spring-cloud-starter-zuul依赖中则包含了ribbon、hystrix、actuator等。
2,创建启动类,如下:
@SpringBootApplication
@EnableZuulProxy
public class AppGateway {
public static void main(String[] args) {
SpringApplication.run(AppGateway.class, args);
}
@Bean
PermisFilter permisFilter() {
return new PermisFilter();
}}
3,配置路由规则,application.properties文件如下:
# 基础信息配置
spring.application.name=api-gateway
server.port=2006
# 路由规则配置
zuul.routes.api-a.path=/api-a/**
zuul.routes.api-a.serviceId=eureka.client.provider.test# API网关也将作为一个服务注册到eureka-server上
eureka.client.service-url.defaultZone=http://admin:123@localhost:8000/eureka/
说明:
我们在这里配置了路由规则所有符合/api-a/**的请求都将被转发到eureka.client.provider.test服务上,
至于feign-consumer服务的地址到底是什么则由eureka-server去分析,我们这里只需要写上服务名即可。
以上面的配置为例,如果我请求http://localhost:2006/api-a/testHello接口则相当于请求http://localhost:2005/testHello(我这里eureka.client.provider.test的地址为http://localhost:2005)。
我们在路由规则中配置的api-a是路由的名字,可以任意定义,但是一组path和serviceId映射关系的路由名要相同。
请求过滤
1.定义过滤器java类,如下:
public class PermisFilter extends ZuulFilter {
@Override
public String filterType() {
return "pre";
} @Override
public int filterOrder() {
return 0;
} @Override
public boolean shouldFilter() {
return true;
} @Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
String login = request.getParameter("login");
if (login == null) {
ctx.setSendZuulResponse(false);
ctx.setResponseStatusCode(401);
ctx.addZuulResponseHeader("content-type","text/html;charset=utf-8");
ctx.setResponseBody("非法访问");
}
return null;
}}
关于这个类我说如下几点:
1.filterType方法的返回值为过滤器的类型,过滤器的类型决定了过滤器在哪个生命周期执行,pre表示在路由之前执行过滤器,其他可选值还有post、error、route和static,当然也可以自定义。
2.filterOrder方法表示过滤器的执行顺序,当过滤器很多时,这个方法会有意义。
3.shouldFilter方法用来判断过滤器是否执行,true表示执行,false表示不执行,在实际开发中,我们可以根据当前请求地址来决定要不要对该地址进行过滤,这里我直接返回true。
4.run方法则表示过滤的具体逻辑,假设请求地址中携带了login参数的话,则认为是合法请求,否则就是非法请求,
如果是非法请求的话,首先设置ctx.setSendZuulResponse(false);表示不对该请求进行路由,然后设置响应码和响应值。这个run方法的返回值在当前版本(Dalston.SR3)中暂时没有任何意义,可以返回任意值。
2.配置过滤器Bean
然后在入口类中配置相关的Bean即可,如下:
@Bean
PermisFilter permisFilter() {
return new PermisFilter();
}
3,测试:
不加login参数,返回:非法访问
加上login参数,访问正常:http://192.168.20.211:2006/api-a/testHello?name="dragon2"&login=1
总结:
API网关作为系统的的统一入口,将微服务中的内部细节都屏蔽掉了,而且能够自动的维护服务实例,实现负载均衡的路由转发,
同时,它提供的过滤器为所有的微服务提供统一的权限校验机制,使得服务自身只需要关注业务逻辑即可。