API网关主要为了服务本身对外的调用该怎么调用来解决的,还有解决权限校验的问题,你可以在这里整合调用一系列过滤器的,例如整合shiro,springsecurity之类的东西。
Zuul可以通过加载动态过滤机制,从而实现以下各项功能:
1.验证与安全保障:识别面向各类资源的验证要求并拒绝与要求不符的那些请求。
2.审查与监控:在边缘位置监控有意义数据及统计结果,从而给我们带来准确的生产状态结论。
3.动态路由:以动态方式根据需求将请求路由到不同后台集群处。
4.压力测试:逐渐增加指向集群的负载流量,从而计算性能水平。
5.负载分配:为每一种负载类型分配对应容量,并弃用超出限定值的请求。
6.静态响应处理:在边缘位置直接建立部分响应,从而避免其流入内部集群。
7.多区域弹性: 跨越AWS区域进行请求路由,旨在实现ELB使用多样化并保证边缘位置与使用者尽可能接近。
接着下来进行实战小Demo
第一步,在原来的工程下,新建一个Zuul模块,引入依赖,代码如下:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
<version>1.3.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zuul</artifactId>
<version>1.3.5.RELEASE</version>
</dependency>
接着在启动类上打上@EnableZuulProxy注解,代码如下:
server:
port: 5000
spring:
application:
name: api-geteway
zuul:
routes:
#标识你服务的名字,这里可以自己定义,一般方便和规范来讲还是跟自己服务的名字一样
hello-service:
#服务映射的路径,通过这路径就可以从外部访问你的服务了,目的是为了不爆露你机器的IP,面向服务的路由了,给你选一个可用的出来,
#这里zuul是自动依赖hystrix,ribbon的,不是面向单机
path: /hello-service/**
#这里一定要是你Eureka注册中心的服务的名称,是所以这里配置serviceId因为跟eureka结合了,如果单独使用zuul,那么就必须写自己机器的IP了,
#如url:http://localhost:8080/ 这样的不好就是写死IP了,万一这IP挂了,这高可用性,服务注册那套东西就用不起来了
serviceId: hello-service
eureka:
#客户端
client:
#注册中心地址
service-url:
defaultZone: http://localhost:8888/eureka/,http://localhost:8889/eureka/
接着启动先前文章中的注册中心和两个hello-service服务提供者,接着我们运行,看一下它的请求转发功能,看他有没有轮询进入两个服务,
输入localhost:5000/hello-service/hello,如下:
接着再刷新一遍:
可以看到zuul进行了请求分发了。它是根据你的服务名字hello-servie来映射到具体的机器上,这不就是一个反向代理的功能吗?
zuul还能进行请求过滤,那么我们进行一下token校验来演示一下,首先我们需要先新建一个TokenFilter类来继承ZuulFilter这个类,实现它的四个接口,代码如下:
package hjc.zuul;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import javax.servlet.http.HttpServletRequest;
/**
* Created by cong on 2018/5/18.
*/
public class TokenFilter extends ZuulFilter {
//四种类型:pre,routing,error,post
//pre:主要用在路由映射的阶段是寻找路由映射表的
//routing:具体的路由转发过滤器是在routing路由器,具体的请求转发的时候会调用
//error:一旦前面的过滤器出错了,会调用error过滤器。
//post:当routing,error运行完后才会调用该过滤器,是在最后阶段的
@Override
public String filterType() {
return "pre";
}
//自定义过滤器执行的顺序,数值越大越靠后执行,越小就越先执行
@Override
public int filterOrder() {
return 0;
}
//控制过滤器生效不生效,可以在里面写一串逻辑来控制
@Override
public boolean shouldFilter() {
return true;
}
//执行过滤逻辑
@Override
public Object run() {
RequestContext context = RequestContext.getCurrentContext();
HttpServletRequest request = context.getRequest();
String token = request.getParameter("token");
if (token == null){
context.setSendZuulResponse(false);
context.setResponseStatusCode(401);
context.setResponseBody("unAuthrized");
return null;
}
return null;
}
}
filterType:返回一个字符串代表过滤器的类型,在zuul中定义了四种不同生命周期的过滤器类型,具体如下:
1.pre
:可以在请求被路由之前调用,用在路由映射的阶段是寻找路由映射表的
2.route
:在路由请求时候被调用,具体的路由转发过滤器是在routing路由器具体的请求转发的时候会调用
3.error
:处理请求时发生错误时被调用
4.post
:当routing,error运行完后才会调用该过滤器,是在最后阶段的
这里声明一下zuul过滤器执行网络请求发生的异常,过滤器里面是不能直接将try-catch捕捉的异常抛出给页面的。应用程序抛出的异常是可以返回出的需解决办法就是在catch里面用context.set()方法返回给页面。如下:
try{
业务逻辑......
}catch(Exception e){
RequestContext context = RequestContext.getCurrentContext();
context.set("error.status_code",401);
context.set("error.exception",e);
context.set("error.message","sfdfsdf");
}
接着,你还需要把这个过滤器加入spring中,让spring管理,代码如下:
package hjc;
import hjc.zuul.TokenFilter;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
@EnableZuulProxy
public class ZuulApplication {
public static void main(String[] args) {
SpringApplication.run(ZuulApplication.class, args);
}
//将过滤器交给Spring管理
@Bean
public TokenFilter tokenFilter(){
return new TokenFilter();
}
}
接着,让我们启动启动类,先进行不带token的访问,如下:
可以看到,返回一个没权限的信息,这里要说一下,Token一般都是放在请求头中的,这里我们只是为了演示才没那么干,
接着将token带上再去访问,如下:
可以看到这是已经将我们的请求放过去了。
这里我还要讲一下什么是默认路由,将zuul的配置删除路由配置,如下:
server:
port: 5000
spring:
application:
name: api-geteway
eureka:
#客户端
client:
#注册中心地址
service-url:
defaultZone: http://localhost:8888/eureka/,http://localhost:8889/eureka/
接着,重启继续访问,如下:
、
可以看到,还是能继续访问,我们什么都没配,居然还能访问,那是因为,这里默认用你的服务名字hello-service自动声明了。
那么,如果说我不想让它帮我自动声明,我要我自己定义,那么可以在yml配置文件中使用zuu.ignored-services就可以把自己像过滤的过滤,如下:”
zuul:
#如果ignored-services:* 表示所有的默认路由都失效了,要自己一个个配,没人会那么操蛋,除非遇到奇葩业务
ignored-services:
zuul官方已经放弃维护了,用gateway吧,或者Kong替代
原文转自:https://www.cnblogs.com/huangjuncong/p/9060984.html