路由在微服务体系结构的一个组成部分。例如,/可以映射到您的Web应用程序,/api/users映射到用户服务,并将/api/shop映射到商店服务。Zuul是Netflix的基于JVM的路由器和服务器端负载均衡器。
Zuul是Netflix开源的微服务网关,他可以和Eureka,Ribbon,Hystrix等组件配合使用
Nginx大家都知道是反向代理服务器,可以做到负载均衡,过滤等功能,其实网关Zuul和它是一样的,比如你的eureka-client服务部署在很多服务器上,前端需要联调,难道都要记住这么多IP和接口,不可能记住的,这个时候就需要网关进行暴露统一接口进行转发请求不同的服务器上,一方面是安全另一方面负载均衡
Zuul的规则引擎允许通过任何JVM语言来编写规则和过滤器, 支持基于Java和Groovy的构建。 配置属性 zuul.max.host.connections 已经被两个新的配置属性替代, zuul.host.maxTotalConnections (总连接数)和 zuul.host.maxPerRouteConnections,(每个路由连接数) 默认值分别是200和20.
1.创建zuul服务加入依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-zuul</artifactId> </dependency>
2.改造pom.xml文件
<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>com.li</groupId> <artifactId>SpringCloudLearn</artifactId> <version>1.0-SNAPSHOT</version> <relativePath>../</relativePath> </parent> <artifactId>zuul-server</artifactId> <version>0.0.1-SNAPSHOT</version> <name>zuul-server</name> <description>Demo project for Spring Boot</description>
<properties> <java.version>1.8</java.version> <spring-cloud.version>Greenwich.SR1</spring-cloud.version> </properties>
<dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-zuul</artifactId> </dependency> </dependencies>
<dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
<build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build>
</project>
在程序的启动类加上@EnableEurekaClient向注册中心注册和@EnableZuulProxy开启zuul的功能
package com.li.zuulserver;
import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.cloud.netflix.eureka.EnableEurekaClient;import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
@EnableZuulProxy@EnableEurekaClient@SpringBootApplicationpublic class ZuulServerApplication {
public static void main(String[] args) { SpringApplication.run(ZuulServerApplication.class, args); }
}
配置application.properties文件
# 端口号server.port=8767# 需要指明spring.application.name 这个很重要# 这在以后的服务与服务之间相互调用一般都是根据这个namespring.application.name=zuul-server#服务注册中心实例的主机名eureka.instance.hostname=localhost#服务注册中心端口号eureka.port=8761#在此指定服务注册中心地址eureka.client.service-url.defaultZone=http://${eureka.instance.hostname}:${eureka.port}/eureka/# 创建两个路由转发# ribbon转ribbon-server服务zuul.routes.ribbon.service-id=ribbon-serverzuul.routes.ribbon.path=/ribbon/**
# feign转feign-server服务zuul.routes.feign.service-id=feign-serverzuul.routes.feign.path=/feign/**
这个意味着 HTTP 调用"/ribbon"被转发到"ribbon-server"服务. 路由必须配置一个可以被指定为ant风格表达式的"path", 所以“/ribbon/*”只能匹配一个层级,依次类推
依次启动eureka-server,eureka-client,feign-server,ribbon-server,zuul-server5个工程进行测试
打开浏览器 访问 http://localhost:8761/ 发现已经注册成功
接着访问: http://localhost:8767/ribbon/hello?name=lhd
访问: http://localhost:8767/feign/hello?name=lhd
说明zuul做到了路由转发的功能
zuul还有过滤的功能, 比如安全认证,我们请求接口需要携带tokrn,我们就可以使用zuul进行过滤,不需要到达原接口就可以进行拦截
如何编写预过滤器?
前置过滤器用于设置RequestContext中的数据,用于下游的过滤器。主要用例是设置路由过滤器所需的信息
实现过滤器 只需要继承ZuulFilter即可
package com.li.zuulserver.filter;
import com.netflix.zuul.ZuulFilter;import com.netflix.zuul.context.RequestContext;import com.netflix.zuul.exception.ZuulException;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.http.HttpStatus;import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;import java.io.IOException;
/** * @Classname MyFilter * @Description TODO * @Author 李号东 lihaodongmail@163.com * @Date 2019-03-31 08:20 * @Version 1.0 */
@Component // 注入beanpublic class RoutingFilter extends ZuulFilter {
private static Logger log = LoggerFactory.getLogger(RoutingFilter.class);
/** * 过滤器的类型 * pre:可以在请求被路由之前调用。我们可利用这种过滤器实现身份验证、在集群中选择请求的微服务、记录调试信息等。 * roting:在路由请求时候被调用。这种过滤器用于构建发送给微服务的请求,并使用Apache HttpClient或Netfilx Ribbon请求微服务。 * post:在routing和error过滤器之后被调用。这种过滤器可用来为响应添加标准的HTTP Header、收集统计信息和指标、将响应从微服务发送给客户端等。 * error:处理请求时发生错误时被调用 * * @return */ @Override public String filterType() { return "pre"; }
/** * 过滤的顺序 越小越先很执行 * * @return */ @Override public int filterOrder() { return 0; }
/** * 是否过滤 true 过滤 false 不执行过滤器 * * @return */ @Override public boolean shouldFilter() { return true; }
/** * 过滤器的具体逻辑 * * @return * @throws ZuulException */
@Override public Object run() throws ZuulException { // 获取请求的上下文类 注意是:com.netflix.zuul.context包下的 RequestContext ctx = RequestContext.getCurrentContext(); //避免中文乱码 ctx.addZuulResponseHeader("Content-type", "text/json;charset=UTF-8"); ctx.getResponse().setCharacterEncoding("UTF-8"); //获取request对象 HttpServletRequest request = ctx.getRequest(); log.info("请求方式:{},地址:{}", request.getMethod(), request.getRequestURL().toString()); // 获取token参数 Object accessToken = request.getParameter("token"); if (accessToken == null) { // 使其不进行转发 自定义route类型时,在shouldFilter中也需要进行此参数判断 ctx.setSendZuulResponse(false); ctx.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value()); try { ctx.getResponse().getWriter().write("非法访问"); } catch (Exception e) { } return null; } else { if ("123".equals(accessToken)) { try { ctx.getResponse().getWriter().write("token is error"); } catch (IOException e) { e.printStackTrace(); } return null; } } return null; }}
说下过滤类型
pre:可以在请求被路由之前调用。我们可利用这种过滤器实现身份验证、在集群中选择请求的微服务、记录调试信息等。 roting:在路由请求时候被调用。这种过滤器用于构建发送给微服务的请求,并使用Apache HttpClient或Netfilx Ribbon请求微服务。 post:在routing和error过滤器之后被调用。这种过滤器可用来为响应添加标准的HTTP Header、收集统计信息和指标、将响应从微服务发送给客户端等。 error:处理请求时发生错误时被调用
filterType 该函数需要返回一个字符串来代表过滤器的类型,而这个类型就是在HTTP请求过程中定义的各个阶段。在Zuul中默认定义了四种不同生命周期的过滤器类型,具体如下:
zuul请求生命周期
重启zuul-server服务 不携带token访问
http://localhost:8767/feign/hello?name=lhd
带上一个错误token
正常访问接口 token正确 可以正常访问
搞定!
源码下载: https://github.com/LiHaodong888/SpringCloudLearn