作为网关至少要有三大功能:
1.路由功能,能够将内外网分离。
2.过滤功能,包括登录鉴权等
3.限流的功能
为了能够满足网关的上述的三大功能这里选择了Zuul+RateLimiter 来实现。
1.application.yml
eureka: client: serviceUrl: defaultZone: http://127.0.0.1:8081/eureka/ server: port: 8087 spring: application: name: api_gateway redis: host: localhost port: 6379 zuul: routes: order_service: /api_gateway/** ignored-services: "*_service/**"
2.pom.xml 主要的包:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-zuul</artifactId> </dependency> <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>27.0-jre</version> </dependency>
3.路由功能
zuul: routes: order_service: /api_gateway/** ignored-services: "*_service/**"
原来直接请求/order_service订单服务,通过zuul的路由配置统一通过/api_gateway/来请求,隐藏了真实的内网服务路径。当然这里需要结合物理网络进行内外网隔离。
4.登录鉴权
登录鉴权是通过ZuulFilter 来进行过滤的。
@Component public class LoginFilter extends ZuulFilter { /** * 过滤器类型,前置过滤器 * @return */ @Override public String filterType() { return "pre"; } /** * 过滤器顺序,越小越先执行 * @return */ @Override public int filterOrder() { return 1; } /** * 过滤器是否生效 * @return */ @Override public boolean shouldFilter() { System.out.println("ZuulExceptionZuulException"); RequestContext requestContext = RequestContext.getCurrentContext(); HttpServletRequest request = requestContext.getRequest(); System.out.println("request.getRequestURI():"+request.getRequestURI()); //ACL if ("/api_gateway/order/getOrderDetailById.do".equalsIgnoreCase(request.getRequestURI())){ return true; } return false; } /** * 业务逻辑 * @return * @throws ZuulException */ @Override public Object run() throws ZuulException { System.out.println("ZuulExceptionZuulException"); //JWT RequestContext requestContext = RequestContext.getCurrentContext(); HttpServletRequest request = requestContext.getRequest(); //token对象 String token = request.getHeader("token"); if(StringUtils.isBlank((token))){ token = request.getParameter("token"); } if (StringUtils.isBlank(token)) { requestContext.setSendZuulResponse(false); requestContext.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value()); } return null; } }
5. 网关限流
限流是通过Guava限流工具RateLimiter来实现的。
@Component public class RateLimitFilter extends ZuulFilter { private static final RateLimiter rateLimiter= RateLimiter.create(2); /** * 过滤器类型,前置过滤器 * @return */ @Override public String filterType() { return "pre"; } /** * 过滤器顺序,越小越先执行 * @return */ @Override public int filterOrder() { return -1; } /** * 过滤器是否生效 * @return */ @Override public boolean shouldFilter() { RequestContext requestContext = RequestContext.getCurrentContext(); HttpServletRequest request = requestContext.getRequest(); if ("/api_gateway/order/getOrderDetailById.do".equalsIgnoreCase(request.getRequestURI())){ System.out.println("request.getRequestURI():"+request.getRequestURI()); return true; } return false; } /** * 业务逻辑 * @return * @throws ZuulException */ @Override public Object run() throws ZuulException { RequestContext requestContext = RequestContext.getCurrentContext(); HttpServletResponse response= requestContext.getResponse(); if (!rateLimiter.tryAcquire()) { try { requestContext.setSendZuulResponse(false); String data = "请求频繁,暂时限流"; OutputStream outputStream = response.getOutputStream(); response.setHeader("content-type", "text/html;charset=UTF-8"); byte[] dataByteArr = data.getBytes("UTF-8"); outputStream.write(dataByteArr); } catch (IOException e) { e.printStackTrace(); } } return null; } }
其中 private static final RateLimiter rateLimiter= RateLimiter.create(2); 是每秒产生两个令牌。rateLimiter.tryAcquire() 无法获取令牌则请求太过于频繁给出提示。
效果如下图:
版权声明:本文为qq_40263927原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。