什么是网关
API Gateway,是系统的唯一对外的入口,介于客户端和服务器端之间的中间层,处理非业务功能 提供路由请求、鉴权、监控、缓存、限流等功能
统一接入
* 智能路由
* AB测试、灰度测试
* 负载均衡、容灾处理
* 日志埋点(类似Nignx日志)
流量监控
* 限流处理
* 服务降级
安全防护
* 鉴权处理
* 监控
* 机器网络隔离
主流的网关
zuul:是Netflix开源的微服务网关,和Eureka,Ribbon,Hystrix等组件配合使用,Zuul 2.0比1.0的性能提高很多
kong: 由Mashape公司开源的,基于Nginx的API gateway
nginx+lua:是一个高性能的HTTP和反向代理服务器,lua是脚本语言,让Nginx执行Lua脚本,并且高并发、非阻塞的处理各种请求
1. zuul路由案例:
1. 导入依赖
<parent><groupId>org.springframework.bootgroupId><artifactId>spring-boot-starter-parentartifactId><version>2.0.3.RELEASEversion><relativePath/> parent><dependencyManagement><dependencies><dependency><groupId>org.springframework.cloudgroupId><artifactId>spring-cloud-dependenciesartifactId><version>Finchley.RELEASEversion><type>pomtype><scope>importscope>dependency>dependencies>dependencyManagement><properties><project.build.sourceEncoding>UTF-8project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8project.reporting.outputEncoding><java.version>1.8java.version>properties><dependencies><dependency><groupId>org.springframework.cloudgroupId><artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>dependency><dependency><groupId>org.springframework.cloudgroupId><artifactId>spring-cloud-starter-netflix-zuulartifactId>dependency>dependencies><build><plugins><plugin><groupId>org.springframework.bootgroupId><artifactId>spring-boot-maven-pluginartifactId>plugin>plugins>build>
2. 注册到eureka
server:port: 9000#服务的名称
spring:application:name: api_gatway#指定注册中心地址ַ
eureka:client:serviceUrl:defaultZone: http://localhost:8761/eureka/
3. 主函数开启zuul注解&#xff0c;并且启动
&#64;SpringBootApplication
&#64;EnableZuulProxy// 开启网关代理
public class ApiGatwayApplication {public static void main(String[] args) {SpringApplication.run(ApiGatwayApplication.class, args);}
}
测试&#xff1a;可以看到服务都已经注册到eureka上了&#xff0c;我们不用配置任何路由规则就可以直接通过注册的服务名称来路由
2. 自定义路由规则&#xff1a;
#自定义路由映射(配置文件加入这段配置就好了)
zuul:routes:order-service: /apigateway/order/** #配置后就不能通过serverName访问了。product-service: /apigateway/product/**#忽略满足条件的服务(即&#xff1a;忽略所有-service结尾的服务)ignored-patterns: /*-service/**#解决http请求头为空的问题 (值为空就好了)sensitive-headers:
3. 自定义过滤器url校验 / 限流&#xff1a;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_TYPE;
import org.springframework.http.HttpStatus;
/*** 拦截指定url, 进行参数校验*/
&#64;Component
public class UrlFilter extends ZuulFilter {// private String pre_filterType &#61; PRE_TYPE; // 前置过滤器(url之前执行)
// private String post_filterType &#61; POST_TYPE; // 后置过滤器
// private String error_filterType &#61; ERROR_TYPE;// 异常过滤器/*** 过滤器类型* &#64;return*/&#64;Overridepublic String filterType() {return PRE_TYPE;}/*** 过滤器顺序(多个过滤器时, 越小的越先执行)* &#64;return*/&#64;Overridepublic int filterOrder() {return 3;}/*** 过滤器是否生效* 为false时就不会走run()里面的业务逻辑* &#64;return*/&#64;Overridepublic boolean shouldFilter() {RequestContext requestContext &#61; RequestContext.getCurrentContext();HttpServletRequest request &#61; requestContext.getRequest();// System.out.println(request.getRequestURI());// System.out.println(request.getRequestURL());if ("/apigateway/order/api/v1/order/find".equalsIgnoreCase(request.getRequestURI())){return true;}return false;}/*** 业务逻辑* &#64;return* &#64;throws ZuulException*/&#64;Overridepublic Object run() throws ZuulException {System.out.println("拦截逻辑");RequestContext requestContext &#61; RequestContext.getCurrentContext();HttpServletRequest request &#61; requestContext.getRequest();//token对象String id &#61; request.getHeader("id");if(StringUtils.isBlank((id))){id &#61; request.getParameter("id");}//如果id参数为null就程序停止, 同时返回 HttpStatus.UNAUTHORIZED 状态码if (StringUtils.isBlank(id)) {requestContext.setSendZuulResponse(false);requestContext.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());}return null;}
}
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.springframework.stereotype.Component;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_TYPE;
import org.springframework.http.HttpStatus;
import com.google.common.util.concurrent.RateLimiter;
/*** 网关限流*/
&#64;Component
public class RequestFilter extends ZuulFilter {//每秒产生1000个令牌private static final RateLimiter RATE_LIMITER &#61; RateLimiter.create(1000);&#64;Overridepublic String filterType() {return PRE_TYPE;}&#64;Overridepublic int filterOrder() {return -4;}&#64;Overridepublic boolean shouldFilter() {return true;}&#64;Overridepublic Object run() throws ZuulException {RequestContext requestContext &#61; RequestContext.getCurrentContext();System.out.println("获取令牌");boolean tryAcquire &#61; RATE_LIMITER.tryAcquire();// 如果获取不到就直接停止if(!tryAcquire){requestContext.setSendZuulResponse(false);requestContext.setResponseStatusCode(HttpStatus.TOO_MANY_REQUESTS.value());}return null;}
}
解决zuul超时问题&#xff0c; 完整配置文件 (设置ribbon hystrix zuul 超时时间&#xff0c;最好超时时间值比被代理的服务要大。ps: 不需要添加其他依赖包&#xff0c;就一个zuul依赖就好了)
server:port: 9000spring:application:name: api_gatway# eureka注册地址
eureka:client:serviceUrl:defaultZone: http://localhost:8761/eureka/ribbon:ReadTimeout: 7000 #超时时间ConnectTimeout: 2000 #连接时间MaxAutoRetries: 1 #同一台实例最大重试次数,不包括首次调用MaxAutoRetriesNextServer: 1 #重试负载均衡其他的实例最大重试次数,不包括首次调用OkToRetryOnAllOperations: false #是否所有操作都重试#解决hystrix&#43;feign超时设置
feign:hystrix: #开启feign支持hystrix (注意:一定要开启&#xff0c;旧版本默认支持&#xff0c;新版本默认关闭)enabled: truehystrix:command:default:execution:isolation:thread:timeoutInMilliseconds: 7000# &#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;
# 不配置路由规则&#xff0c;默认可以用服务注册名称来路由
# 商品服务&#xff1a;http://localhost:9000/product-service/api/v1/product/list
# 订单服务&#xff1a;http://localhost:9000/order-service/api/v1/order/find?id&#61;3# 自定义路由规则
zuul:routes:order-service: /apigateway/order/**product-service: /apigateway/product/**# 禁止对product-service服务路由 (支持多个&#xff0c;逗号隔开就好了)#ignored-services: product-service# 禁止对所有-service结尾的服务路由ignored-patterns: /*-service/**# 解决http请求头为空的问题 (值为空就好了)sensitive-headers:#ignored-headers: accept-language 路由时&#xff0c;不向第三方传递请求头#sensitive-headers: COOKIE 路由时&#xff0c;不向第三方传递COOKIEhost:socket-timeout-millis: 7000connect-timeout-millis: 7000# 经过上面的自定义路由之后# 访问product-service http://localhost:9000/apigateway/product/api/v1/product/list# 访问order-service http://localhost:9000/apigateway/order/api/v1/order/find?id&#61;3