上一篇已经讲了微服务组件中的分布式配置中心,本章讲述 由JAVA编写的服务路由网关 Zuul
…
路由是微服务体系结构的一个组成部分。例如 /
可以映射到您的Web应用程序,/api/users映射到用户服务,/api/shop映射到商店服务。Zuul是Netflix的基于JVM的开发的路由和服务器端负载均衡器。
为什么需要服务网关?
如果没有服务网关,多个服务提供给前端调用地址管理错综复杂,增加了客户端的复杂性,认证也相对麻烦,每个服务都需要编写相同的认证….
画图工具: https://www.processon.com/
Zuul 可以做什么?
Zuul的规则引擎允许基本上写任何JVM语言的规则和过滤器,内置Java和Groovy的支持。
注意:配置属性 zuul.max.host.connections
已被取代的两个新的属性, zuul.host.maxTotalConnections
并且 zuul.host.maxPerRouteConnections
它的缺省值分别200和20。
注意:所有路线的默认Hystrix隔离模式(ExecutionIsolationStrategy)为 SEMAPHORE
。 zuul.ribbonIsolationStrategy
如果此隔离模式是首选,可以更改为 THREAD
。
官方文档: http://cloud.spring.io/spring-cloud-static/Dalston.SR2/#_router_and_filter_zuul
1.启动Consul
2.创建 battcn-gateway-service
和 battcn-hello-service
1.在项目 pom.xml 中添加 ZUUL 依赖
<dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-zuul</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-consul-discovery</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>
2.App.java中开启 zuul 代理
@EnableZuulProxy @EnableDiscoveryClient @SpringBootApplication public class ZuulApplication { public static void main(String[] args) { SpringApplication.run(ZuulApplication.class, args); } }
3. zuul.routes.routesName.ZuulProperties.ZuulRoute
配置的方式,详细可以参考源码 org.springframework.cloud.netflix.zuul.filters.ZuulProperties
server: port: 9000 zuul: routes: hello-service: #自定义的 路由名称 path: /api-hello/** #路由路径 serviceId: battcn-hello-service #VIP 模式中的 serviceId spring: application: name: battcn-gateway-service cloud: consul: host: localhost port: 8500 enabled: true discovery: enabled: true prefer-ip-address: true
hello-service 只需要以下依赖,能注册到consul中就行(单纯的一个服务)
<dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-consul-discovery</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>
@EnableDiscoveryClient @SpringBootApplication public class HelloApplication { public static void main(String[] args) { SpringApplication.run(HelloApplication.class, args); } }
server: port: 9001 spring: application: name: battcn-hello-service cloud: consul: host: localhost port: 8500 enabled: true discovery: enabled: true prefer-ip-address: true
访问: http://localhost:9000/api-hello/hello 从地址中可以看出我们访问的是 battcn-gateway-service
,且满足 zuul.routes.routesName.path
规则,因此实际请求地址是 http://localhost:9001/hello
hello:battcn-hello-service #表示请求成功
import com.netflix.zuul.ZuulFilter; import com.netflix.zuul.context.RequestContext; import org.springframework.stereotype.Component; import javax.servlet.http.HttpServletRequest; /** * 网关认证过滤器(Demo演示,实际根据自身业务考虑实现) * @author Levin * @date 2017-08-14. */ @Component public class GatewayZuulFilter extends ZuulFilter { /** * per:路由之前,如实现认证、记录调试信息等 * routing:路由时 * post:路由后,比如添加HTTP Header * error:发生错误时调用 */ @Override public String filterType() { return "pre"; } /** * 过滤器顺序,类似@Filter中的order */ @Override public int filterOrder() { return 0; } /** * 这里可以写逻辑判断,是否要过滤,本文true,永远过滤。 */ @Override public boolean shouldFilter() { return true; } /** * 过滤器的具体逻辑。可用很复杂,包括查sql,nosql去判断该请求到底有没有权限访问。 */ @Override public Object run() { RequestContext ctx = RequestContext.getCurrentContext(); HttpServletRequest request = ctx.getRequest(); String token = request.getParameter("token"); if(token == null) { ctx.setSendZuulResponse(false); ctx.setResponseStatusCode(404); ctx.setResponseBody("token cannot be empty"); } return null; } }
实际开发中 token
应该从请求头中获取,该处只是为了方便演示效果
访问: http://localhost:9000/api-hello/hello?token=1
hello:battcn-hello-service
访问: http://localhost:9000/api-hello/hello
token cannot be empty
图不是很严谨,凑合着看看吧…
初次启动项目我们可以看到
2017-08-14 17:19:06.090 INFO 11544 --- [nio-9000-exec-1] o.s.c.n.zuul.web.ZuulHandlerMapping : Mapped URL path [/api-hello/**] onto handler of type [class org.springframework.cloud.netflix.zuul.web.ZuulController] 2017-08-14 17:19:06.090 INFO 11544 --- [nio-9000-exec-1] o.s.c.n.zuul.web.ZuulHandlerMapping : Mapped URL path [/battcn-gateway-service/**] onto handler of type [class org.springframework.cloud.netflix.zuul.web.ZuulController] 2017-08-14 17:19:06.090 INFO 11544 --- [nio-9000-exec-1] o.s.c.n.zuul.web.ZuulHandlerMapping : Mapped URL path [/battcn-hello-service/**] onto handler of type [class org.springframework.cloud.netflix.zuul.web.ZuulController] 2017-08-14 17:19:06.090 INFO 11544 --- [nio-9000-exec-1] o.s.c.n.zuul.web.ZuulHandlerMapping : Mapped URL path [/consul/**] onto handler of type [class org.springframework.cloud.netflix.zuul.web.ZuulController]
有兴趣的还可以阅读下 com.netflix.loadbalancer.LoadBalancerContext
,通过它可以发现每次请求的IP和端口,需要在 application.yml
中配置
logging: level: com.netflix: DEBUG
2017-08-14 17:32:16.793 DEBUG 14316 --- [nio-9000-exec-7] c.n.zuul.http.HttpServletRequestWrapper : Path = null 2017-08-14 17:32:16.793 DEBUG 14316 --- [nio-9000-exec-7] c.n.zuul.http.HttpServletRequestWrapper : Transfer-Encoding = null 2017-08-14 17:32:16.793 DEBUG 14316 --- [nio-9000-exec-7] c.n.zuul.http.HttpServletRequestWrapper : Content-Encoding = null 2017-08-14 17:32:16.793 DEBUG 14316 --- [nio-9000-exec-7] c.n.zuul.http.HttpServletRequestWrapper : Content-Length header = -1 2017-08-14 17:32:16.793 DEBUG 14316 --- [nio-9000-exec-7] c.n.loadbalancer.ZoneAwareLoadBalancer : Zone aware logic disabled or there is only one zone 2017-08-14 17:32:16.793 DEBUG 14316 --- [nio-9000-exec-7] c.n.loadbalancer.LoadBalancerContext : battcn-hello-service using LB returned Server: 192.168.31.221:9001 for request /hello
定义 GatewayZuulFallback
实现 ZuulFallbackProvider
接口
package com.battcn.config; import org.springframework.cloud.netflix.zuul.filters.route.ZuulFallbackProvider; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.client.ClientHttpResponse; import org.springframework.stereotype.Component; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; /** * @author Levin * @date 2017-08-14. */ @Component public class GatewayZuulFallback implements ZuulFallbackProvider { @Override public String getRoute() { return "battcn-hello-service";//指定回退的服务名 } @Override public ClientHttpResponse fallbackResponse() { return new ClientHttpResponse() { @Override public HttpStatus getStatusCode() throws IOException { return HttpStatus.INTERNAL_SERVER_ERROR; //INTERNAL_SERVER_ERROR(500, "Internal Server Error") } @Override public int getRawStatusCode() throws IOException { return this.getStatusCode().value();// 500 } @Override public String getStatusText() throws IOException { return this.getStatusCode().getReasonPhrase();// Internal Server Error } @Override public void close() {} @Override public InputStream getBody() throws IOException { return new ByteArrayInputStream(getStatusText().getBytes());//也可以随意写自己想返回的内容 } @Override public HttpHeaders getHeaders() { HttpHeaders httpHeaders = new HttpHeaders(); httpHeaders.setContentType(MediaType.APPLICATION_JSON_UTF8); return httpHeaders; } }; } }
zuul 相关的官方文档还是比较其全了,本文也是参考官方然后简单讲述应用场景,具体开发请结合自身业务扩展….
1.自定义指定微服务路径,以下两种配置方式结果相同
zuul: routes: battcn-hello-service: /api-hello/** #两种配置方式结果相同 zuul: routes: hello-service: path: /api-hello/** serviceId: battcn-hello-service
2.忽略指定服务,多个服务逗号分隔, Set<String> ignoredServices
这样一来zuul就会忽略service1和service2,只会代理其它的
zuul: ignored-services: battcn-hello-service1,battcn-hello-service2
3.指定Path和Url
zuul: routes: hello-service: path: /api-hello/** #路由路径 url: http://localhost:9001/ #指定URL地址
4.使用Zuul但不指定Url(该方式在Eureka有效,Consul还未找到解决方法…)
zuul: routes: battcn-hello-service: /api-hello/** ribbon: eureka: enabled: false #为Ribbon禁用 eureka,不会破坏Zuul的Hystrix和Ribbon特性 battcn-hello-service: ribbon: listOfServers: localhost:9001,localhost:9002
本章代码(battcn-gateway-service/battcn-hello-service): https://git.oschina.net/battcn/battcn-cloud/tree/master/battcn-cloud-zuul
如有问题请及时与我联系
1.个人QQ:1837307557
2.Spring Cloud中国社区①:415028731
3.Spring For All 社区⑤:157525002
转载标明出处,thanks
谢谢你请我吃糖果
支付宝
微信