引入pom文件
<!--引入springcloud的euekea client依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</artifactId>
</dependency>
<!--引入springcloud的euekea client依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!-- 声明对spring-cloud-starter-zuul的依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zuul</artifactId>
</dependency>
注意上面部分的依赖,因为网关也是基于Eureka的说一客户端一定要引入,否则网关根本跑不起来
另外网关默认也是基于ribbon的,所以也要引入。
关于代码
入口APP
很简单:
@SpringBootApplication
@EnableZuulProxy
public class App
{
public static void main( String[] args )
{
SpringApplication.run(App.class, args);
}
}
关于配置
Eurake的配置
这个是基本的配置:
server:
port: 5000 #网关5字头,第一个
指定当前eureka客户端的注册地址,也就是eureka服务的提供方,当前配置的服务的注册服务方
eureka:
instance:
hostname: 172.17.7.90
client:
service-url:
defaultZone: http://${eureka.instance.hostname}:2000/eureka
#指定应用名称
spring:
application:
name: zuul-agw
这个和普通的基本eureka没啥区别,有了这个网关就能跑起来,其他不说了。
关于超时
Zuul超时有两种方式,比较靠谱的方式用ribbon进行超时。Zuul是用ribbon做负载均衡的,所以配置了ribbon就配置了超时。
ribbon:
eureka:
enabled: true
ReadTimeout: 3500
ConnectTimeout: 3500
顺便说一下红色部分,红色部分很重要,如果使用eureka的服务列表,那么这个开关一定要打开,否则在eureka上线和下线的时候,通知不及时会导致服务异常!
路由配置
zuul:
# 使用 prefix 添加前缀
prefix: /zyth
routes:
eureka:
path: /monitor-eureka/**
url: url
serviceId: oneServiceName
上面就是一个最简单的配置。
说明一下,prefix是统一前缀,就是先判断能否进入这个网关代理,有这个前缀的才进入网关代理。如果不配置,就是所有的请求都经过代理。
Routes就是具体不同的二级后缀和实际转发的配置了。
Path:是匹配的模式。
模式匹配到了,就有两个转发模式:url或者serviceId
url就会转入到指定的http地址中,而serviceId就会转入到一个具体的微服务地址中。如果url后面的值,不是http等,这个地方就会当作是一个serviceID处理,也就是说,url这里直接配置serviceId也是ok的
关于统一前缀是否去掉
关于统一前缀是否去掉。
关于路由
服务路由有两种,默认情况下,配置了eureka后,直接就是/前缀/服务id/服务端点。这样方式。
如果觉得服务前缀不爽,就要手动修改路由了,有两种方式,当然两种方式都是通过urlmapping实现的。
第一种方式:通过直接的ip地址:
网关配置
zuul:
# 使用 prefix 添加前缀
prefix: /zyth
routes:
eureka:
path: /monitor-eureka/**
url: http://${eureka.instance.hostname}:2000/
如上,是对eureka的配置,这个名字随便取
下面有paht,这个无论哪种配置都是一样的,就是使用path路径映射
然后,就是对应这个路径下的访问url了。
下面url针对集群,是可以配置多个的,用’,’隔开就行。
另外,以上就是,配置访问对eurake的配置逻辑。
第二种方式:通过配置服务id,就是注册到eureka上的服务名进行访问:
prefix: /zyth
routes:
oneservice:
path: /monitor-eureka/**
serviceId: serviceName
这种方式中serviceId就是eureka上,可以按照动态列表进行获取
另外对第一种方式的补充说明:
如果没有经过Eureka服务器,那自然就得不到Ribbon的负载均衡功能了。针对这个问题,Zuul已经帮开发者想到了解决方案,在这种情况下开发者只需要禁用Ribbon与Eureka的自动集成设置,采用手工设置方式开启即可,配置如下:
zuul:
routes:
myroutes1:
path: /mypath/**
serviceId: myserverId
myserverId:
ribbon:
listOfServers: localhost:8080, localhost:8081
ribbon:
eureka:
enabled: false
默认路由和安全
默认路由就是zuul啥都不配的情况下,默认就是微服务名称转向对应的微服务即:
[servicename]:[servicename]
这是一个巨坑,很多时候,我们要显示配置,微服务内部服务是不暴露出来的。这个需要手动配置关闭:
zuul:
ignored-services: '*'
ignoredPatterns: /**/channel/pay/**,/**/channel/transfer/**
第二个配置项,和安全相关,就是直接屏蔽掉某些不该有的pattern
跨域
跨域实际就是在响应的时候统一加上跨域头部。
实际代码可以是在setting中加入如下:
@Component
public class CorsFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
/* String curOrigin = request.getHeader("Origin");
System.out.println("###跨域过滤器->当前访问来源->"+curOrigin+"###"); */
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "*");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "x-requested-with");
chain.doFilter(req, res);
}
@Override
public void init(FilterConfig filterConfig) {
}
@Override
public void destroy() {
}
}
说明,这个应该可以统一用网关的拦截器做的,还没有验证过,后面可以验证一下。
拦截
Zuul的拦截器,很多门道,基础就是继承一个类,实现拦截:ZuulFilter
继承方法介绍
public String filterType() 这个函数返回拦截器类型,可以之前拦截,可以之后拦截,主要看返回的是什么类型
public int filterOrder() 这个函数是返回拦截器的执行顺序,可见是可以支持多个拦截器的
public boolean shouldFilter() 这个函数是返回是否要执行本拦截
public Object run() throws ZuulException 真正的拦截器逻辑代码
设置注解
这个要只要继承就可以使用,但是如果要加入到spring的注入中,就要增加要给注解,简单的就是用:
@Component
Filter间传递值
RequestContext ctx = RequestContext.getCurrentContext();
获取基本的servlet请求对象
直接看代码吧
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
String url = request.getRequestURI();
log.info(String.format("LoginCheck(%s)->开始校验",url));
如何拦截
当该请求非法,就要拦截,拦截是在run函数里面执行的。Run函数返回null就行,无论成功还是失败。
但真正的拦截就要靠如下代码:
//登录验证失败了
ctx.set(GWConst.FILTER_RESULT_NAME_LASTRESULT,false);
ctx.setSendZuulResponse