小言_互联网的博客

单体springboot项目上如何使用springcloud gateway进行负载均衡 拦截 限流 熔断等操作

329人阅读  评论(0)

        一般我们使用网关,大都是配合注册中心进行使用,gateway注册到注册中心,注册中心中可自动实现负载均衡,但是通常会有一些项目不是使用分布式的架构,那么我们单体的springboot项目,如何使用springcloud gateway进行负载均衡和限流 鉴权呢

       下图我spring 官网上springcloud的架构图解,可以很清晰的看到服务请求进来的整个过程。

      

接下来我们看下springcloud gateway的几个主要词汇,路由 断言 处理 和网关处理处理流程图 这里是springcloud gateway官网地址点击直达

     如果我们是单体应用的话,单体部署多台服务器上,也可以通过网关分发,达到负载 拦截等效果

   接下来我们看下具体的配置参数和处理,先看下 yml 的具体配置


  
  1. server:
  2. port: 9999
  3. spring:
  4. cloud:
  5. gateway:
  6. #discovery:
  7. #locator:
  8. #enabled: true
  9. routes:
  10. - id: my-consumer-service
  11. uri: lb://my-consumer-service # http://127.0.0.1:8088
  12. predicates:
  13. - Path=/app/** #断言处理
  14. filters:
  15. - StripPrefix= 1 #表示路由时会去除一位 如 api/app/login app/login
  16. - name: RequestRateLimiter #名称必须是RequestRateLimiter
  17. args:
  18. key-resolver: "#{@urlResolver}" #使用SpEL按名称引用bean
  19. redis-rate-limiter.replenishRate: 20 #允许用户每秒处理多少个请求
  20. redis-rate-limiter.burstCapacity: 10 #令牌桶的容量,允许在一秒钟内完成的最大请求数
  21. - name: Hystrix #断路器的配置
  22. args:
  23. name: fallbackcmd
  24. fallbackUri: forward:/defaultfallback
  25. - id: my-consumer-service2
  26. uri: http:// 127.0 .0 .1: 8088 # http://127.0.0.1:8088 lb://consumer-service lb 代表从注册中心获取服务,且已负载均衡方式转发
  27. predicates:
  28. - Path=/admin/** #断言处理
  29. filters:
  30. - StripPrefix= 1 #表示路由时会去除一位 如 api/app/login app/login
  31. - name: RequestRateLimiter #名称必须是RequestRateLimiter
  32. args:
  33. key-resolver: "#{@urlResolver}" #使用SpEL按名称引用bean
  34. redis-rate-limiter.replenishRate: 20 #允许用户每秒处理多少个请求
  35. redis-rate-limiter.burstCapacity: 10 #令牌桶的容量,允许在一秒钟内完成的最大请求数
  36. - name: Hystrix #断路器的配置
  37. args:
  38. name: fallbackcmd
  39. fallbackUri: forward:/defaultfallback
  40. redis:
  41. host: localhost
  42. port: 6379
  43. database: 0
  44. my-consumer-service:
  45. ribbon:
  46. listOfServers: localhost: 9088,localhost, 9099
  47. NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RoundRobinRule

  如果你要负载到多台上,写法  lb://my-consumer-service ,(单台的话uri 直接ip端口)然后在下面定义你这个服务地址,这是是写死的,不能像注册中心一样灵活感知新增的服务,如果不需要断言处理,不截取前端的话,修改配置,同时去掉 

- StripPrefix=1 #表示路由时会去除一位 如 api/app/login app/login
- Path=/**/** #只路由转发

 网关拦截 token 白名单操作, 请看如下


  
  1. package com.example.springcloudgateway. filter;
  2. import com.alibaba.fastjson.JSON;
  3. import com.example.springcloudgateway.config.AppConstants;
  4. import com.example.springcloudgateway.dto.CommonResult;
  5. import lombok.extern.slf4j.Slf4j;
  6. import org.apache.commons.lang.StringUtils;
  7. import org.springframework.beans.factory.annotation.Autowired;
  8. import org.springframework.cloud.gateway.filter.GatewayFilterChain;
  9. import org.springframework.cloud.gateway.filter.GlobalFilter;
  10. import org.springframework.context.annotation.Configuration;
  11. import org.springframework.core.Ordered;
  12. import org.springframework.core.annotation.Order;
  13. import org.springframework.core.codec.EncodingException;
  14. import org.springframework.core.io.buffer.DataBuffer;
  15. import org.springframework.data.redis.core.StringRedisTemplate;
  16. import org.springframework.http.HttpStatus;
  17. import org.springframework.http.server.reactive.ServerHttpRequest;
  18. import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
  19. import org.springframework.http.server.reactive.ServerHttpResponse;
  20. import org.springframework.stereotype.Component;
  21. import org.springframework.web.server.ServerWebExchange;
  22. import reactor.core.publisher.Flux;
  23. import reactor.core.publisher.Mono;
  24. import java.io.UnsupportedEncodingException;
  25. import java.net.URI;
  26. import java.util.Arrays;
  27. /**
  28. * @version V1.0
  29. * @author: hqk
  30. * @date: 2020/5/12 15:35
  31. * @Description: 转发之前拦截 白名单过滤 鉴权
  32. */
  33. @ Slf4j
  34. @ Component
  35. public class TokenFilter implements GlobalFilter, Ordered {
  36. @ Autowired
  37. private StringRedisTemplate stringRedisTemplate;
  38. // 白名单 排除无需验证的 token
  39. private static final String[] whiteList = { "/auth/login", "/user/register"};
  40. @ Override
  41. public Mono< Void> filter( ServerWebExchange exchange, GatewayFilterChain chain) {
  42. ServerHttpRequest serverHttpRequest = exchange.getRequest();
  43. String url =serverHttpRequest.getURI().getPath();
  44. log.info( "url:{}", url);
  45. //System.out.println("请求地址:"+url);
  46. //无需过滤的URL
  47. if ( Arrays.asList(whiteList). contains(url)){
  48. return chain. filter(exchange);
  49. }
  50. String token =serverHttpRequest.getHeaders().getFirst( AppConstants. TOKEN);
  51. log.info( "请求token:{}", token);
  52. //System.out.println("请求token:"+token);
  53. if( StringUtils.isEmpty(token)){
  54. return setResponse(exchange, "token 不存在");
  55. }
  56. String redisToken=stringRedisTemplate.opsForValue(). get( AppConstants. REDIS_KEY_TOKEN);
  57. if ( StringUtils.isBlank(redisToken)) {
  58. return setResponse(exchange, "token 失效");
  59. }
  60. log.info( "鉴权完毕");
  61. return chain. filter(exchange);
  62. }
  63. /**
  64. * 设置 拦截返回信息
  65. * @param exchange
  66. * @param msg
  67. * @return
  68. */
  69. private Mono< Void> setResponse( ServerWebExchange exchange, String msg) {
  70. ServerHttpResponse originalResponse = exchange.getResponse();
  71. originalResponse.setStatusCode( HttpStatus. UNAUTHORIZED);
  72. originalResponse.getHeaders().add( "Content-Type", "application/json;charset=UTF-8");
  73. byte[] response = null;
  74. try
  75. {
  76. log.info( "token已失效");
  77. response = JSON.toJSONString( CommonResult.error(msg, "")).getBytes( AppConstants. UTF8);
  78. }
  79. catch ( UnsupportedEncodingException e){
  80. e.printStackTrace();
  81. }
  82. DataBuffer buffer = originalResponse.bufferFactory().wrap(response);
  83. return originalResponse.writeWith( Flux.just(buffer));
  84. }
  85. @ Override
  86. public int getOrder() {
  87. return - 200;
  88. }
  89. }

 限流代码,这里根据请求地址限流,如果是ip限流,把URL换成 ip ,然后在配置文件中配置,这里之前已经配置了


  
  1. package com.example.springcloudgateway.resolver;
  2. import lombok.extern.slf4j.Slf4j;
  3. import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
  4. import org.springframework.stereotype.Component;
  5. import org.springframework.web.server.ServerWebExchange;
  6. import reactor.core.publisher.Mono;
  7. /**
  8. * @version V1.0
  9. * @author: hqk
  10. * @date: 2020/5/12 13:20
  11. * @Description: 限流配置
  12. */
  13. @Slf4j
  14. @Component
  15. public class UrlResolver implements KeyResolver {
  16. @Override
  17. public Mono<String> resolve(ServerWebExchange exchange) {
  18. //String ip=exchange.getRequest().getRemoteAddress().getAddress().getHostAddress();
  19. //获取请求地址
  20. String url= exchange.getRequest().getURI().toString();
  21. log.info( "断言处理后的url:{}",url);
  22. //System.out.println("url:"+url);
  23. return Mono.just(url);
  24. }
  25. }

接下来我们看下网关熔断的代码,配置已在第一步中配置过了


  
  1. package com .example .springcloudgateway .controller;
  2. import com .example .springcloudgateway .dto .CommonResult;
  3. import org .springframework .web .bind .annotation .RequestMapping;
  4. import org .springframework .web .bind .annotation .RestController;
  5. import java .util .HashMap;
  6. import java .util .Map;
  7. /**
  8. * @version V1.0
  9. * @author: hqk
  10. * @date: 2020/5/11 16:38
  11. * @Description: 网关熔断降级返回
  12. */
  13. @ RestController
  14. public class DefaultHystrixController {
  15. @ RequestMapping("/ defaultfallback")
  16. public Object defaultfallback(){
  17. System .out .println("降级操作...");
  18. return CommonResult .error(401,"网关服务熔断");
  19. }
  20. /*@RequestMapping("/defaultfallback")
  21. public Map<String,String> defaultfallback(){
  22. System.out.println("降级操作...");
  23. Map<String,String> map = new HashMap<>();
  24. map.put("resultCode","false");
  25. map.put("resultMessage","服务异常");
  26. map.put("resultObj","这里测试网关服务熔断");
  27. return map;
  28. }*/
  29. }

这样我们网关 路由转发 断言 拦截 限流,网关熔断都处理完毕,具体代码已上传到码云,点击直达


转载:https://blog.csdn.net/huqiankunlol/article/details/106089438
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场