• SpringCloudGateWay个人笔记


    核心概念:

    Route(路由):
    路由是构建⽹关的基本模块,它由 ID ,⽬标 URI ,⼀系列的断⾔和过滤器组成,如果断⾔为 true就  匹配该路由。
    Predicate(断⾔、谓词): 开发⼈员可以匹配 HTTP 请求中的所有内容(例如请求头或请求参数),如果请求与断⾔相匹配则进 ⾏路由。
    Filter(过滤): 指的是 Spring 框架中 GatewayFilter 的实例,使⽤过滤器,可以在请求被路由前或者之后对请求 进⾏修改。
    ⼯作流程:
    1: 客户端向 Spring Cloud Gateway 发出请求。然后在 Gateway Handler Mapping 中找到与请求相匹配的路由
    2: 将其发送到 Gateway Web Handler
    3:Handler 再通过指定的过滤器链来将请求发送到我们实际的服务执⾏业务逻辑,然后返回。过滤器之间⽤虚线分开是因为过滤器可能会在发送代理请求之前(“pre” )或之后( “post” )执⾏业务逻辑。
    依赖:
    1. <dependencies>
    2. <!-- spring-cloud gateway,底层基于netty -->
    3. <dependency>
    4. <groupId>org.springframework.cloud</groupId>
    5. <artifactId>spring-cloud-starter-gateway</artifactId>
    6. </dependency>
    7. <!-- 端点监控 -->
    8. <dependency>
    9. <groupId>org.springframework.boot</groupId>
    10. <artifactId>spring-boot-starter-actuator</artifactId>
    11. </dependency>
    12. <!-- nacos注册中⼼ -->
    13. <dependency>
    14. <groupId>com.alibaba.cloud</groupId>
    15. <artifactId>spring-cloud-starter-alibaba-nacosdiscovery</artifactId>
    16. </dependency>
    17. </dependencies>

    配置文件(动态路由)例子:

    1. server:
    2. #gateway的端⼝
    3. port: 8888
    4. spring:
    5. application:
    6. name: cloud-gateway
    7. cloud:
    8. nacos:
    9. discovery:
    10. server-addr: 127.0.0.1:8848
    11. gateway:
    12. routes:
    13. - id: service-user
    14. uri: lb://service-user
    15. predicates:
    16. - Path=/user/**

    谓词工厂:

    1. spring:
    2. cloud:
    3. gateway:
    4. routes:
    5. - id: wfx-jifen
    6. uri: lb://wfx-goods
    7. predicates:
    8. - Path=/goods/detail/100
    9. - After=2022-11-28T15:26:40.626+08:00[Asia/Shanghai]
    10. - Cookie=name,jack
    11. - Header=token
    12. - Host=**.baidu.com,**.taobao.com
    13. - Query=name,tom
    14. - RemoteAddr=192.168.56.10,192.168.56.11

    过滤器:

    分成了全局和局部过滤器。局部只针对某一路由,全局针对所有路由。

    使用内置过滤器:

    1. spring:
    2. cloud:
    3. gateway:
    4. routes:
    5. - id: add_request_header_route
    6. uri: https://example.org
    7. filters:
    8. - AddRequestHeader=Foo, Bar

    一般内置过滤器无法满足需求,所以经常使用自定义过滤器。自定义全局过滤器(请求是否带token的例子):

    1. import org.springframework.beans.factory.annotation.Autowired;
    2. import org.springframework.cloud.gateway.filter.GatewayFilterChain;
    3. import org.springframework.cloud.gateway.filter.GlobalFilter;
    4. import org.springframework.core.Ordered;
    5. import org.springframework.core.io.buffer.DataBuffer;
    6. import org.springframework.data.redis.core.RedisTemplate;
    7. import org.springframework.http.server.reactive.ServerHttpRequest;
    8. import org.springframework.http.server.reactive.ServerHttpResponse;
    9. import org.springframework.stereotype.Component;
    10. import org.springframework.util.StringUtils;
    11. import org.springframework.web.server.ServerWebExchange;
    12. import reactor.core.publisher.Mono;
    13. import java.nio.charset.StandardCharsets;
    14. import com.google.gson.JsonObject;
    15. @Component
    16. public class AuthFilter implements GlobalFilter, Ordered {
    17. @Autowired
    18. private RedisTemplate redisTemplate;
    19. //针对所有的路由进⾏过滤
    20. @Override
    21. public Mono filter(ServerWebExchange exchange,
    22. GatewayFilterChain chain) {
    23. //过滤器的前处理
    24. ServerHttpRequest request = exchange.getRequest();
    25. ServerHttpResponse response = exchange.getResponse();
    26. //获取当前的请求连接
    27. String path = request.getURI().getPath();
    28. if(!(path.contains("api/ucenter/login")||path.contains("api/ucenter/register")||path.contains("admin/acl/user/**"))){
    29. String token = request.getHeaders().getFirst("token");
    30. if(StringUtils.isEmpty(token)){
    31. JsonObject message = new JsonObject();
    32. message.addProperty("success", false);
    33. message.addProperty("code", 28004);
    34. message.addProperty("data", "没有登录");
    35. return response(response,message);
    36. }else{
    37. String tokenRedis = redisTemplate.opsForValue().get("token");
    38. if(!tokenRedis.equals(token)){
    39. JsonObject message = new JsonObject();
    40. message.addProperty("success", false);
    41. message.addProperty("code", 28004);
    42. message.addProperty("data", "令牌无效");
    43. return response(response,message);
    44. }else{
    45. return chain.filter(exchange); //放⾏
    46. }
    47. }
    48. }
    49. return chain.filter(exchange);
    50. }
    51. private Mono response(ServerHttpResponse response,Object message){
    52. response.getHeaders().add("Content-Type",
    53. "application/json;charset=UTF-8");
    54. byte[] bits = message.toString().getBytes(StandardCharsets.UTF_8);
    55. DataBuffer dataBuffer =
    56. response.bufferFactory().wrap(bits);
    57. return response.writeWith(Mono.just(dataBuffer));//响应json数据
    58. }
    59. @Override
    60. public int getOrder() {
    61. return 0;
    62. }
    63. }

    自定义异常处理:

    服务网关调用服务时返回的错误信息对开发人员并不是很友好,所以可以自定义异常处理:

    1. import org.springframework.boot.autoconfigure.web.ErrorProperties;
    2. import org.springframework.boot.autoconfigure.web.ResourceProperties;
    3. import org.springframework.boot.autoconfigure.web.reactive.error.DefaultErrorWebExceptionHandler;
    4. import org.springframework.boot.web.reactive.error.ErrorAttributes;
    5. import org.springframework.context.ApplicationContext;
    6. import org.springframework.http.HttpStatus;
    7. import org.springframework.web.reactive.function.server.*;
    8. import java.util.HashMap;
    9. import java.util.Map;
    10. //自定义异常处理
    11. public class JsonExceptionHandler extends DefaultErrorWebExceptionHandler {
    12. public JsonExceptionHandler(ErrorAttributes errorAttributes, ResourceProperties resourceProperties,
    13. ErrorProperties errorProperties, ApplicationContext applicationContext) {
    14. super(errorAttributes, resourceProperties, errorProperties, applicationContext);
    15. }
    16. /**
    17. * 获取异常属性
    18. */
    19. @Override
    20. protected Map getErrorAttributes(ServerRequest request, boolean includeStackTrace) {
    21. Map map = new HashMap<>();
    22. map.put("success", false);
    23. map.put("code", 20005);
    24. map.put("message", "网关失败");
    25. map.put("data", null);
    26. return map;
    27. }
    28. /**
    29. * 指定响应处理方法为JSON处理的方法
    30. * @param errorAttributes
    31. */
    32. @Override
    33. protected RouterFunction getRoutingFunction(ErrorAttributes errorAttributes) {
    34. return RouterFunctions.route(RequestPredicates.all(), this::renderErrorResponse);
    35. }
    36. /**
    37. * 根据code获取对应的HttpStatus
    38. * @param errorAttributes
    39. */
    40. @Override
    41. protected int getHttpStatus(Map errorAttributes) {
    42. return HttpStatus.OK.value();
    43. }
    44. }
    1. import org.springframework.beans.factory.ObjectProvider;
    2. import org.springframework.boot.autoconfigure.web.ResourceProperties;
    3. import org.springframework.boot.autoconfigure.web.ServerProperties;
    4. import org.springframework.boot.context.properties.EnableConfigurationProperties;
    5. import org.springframework.boot.web.reactive.error.ErrorAttributes;
    6. import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler;
    7. import org.springframework.context.ApplicationContext;
    8. import org.springframework.context.annotation.Bean;
    9. import org.springframework.context.annotation.Configuration;
    10. import org.springframework.core.Ordered;
    11. import org.springframework.core.annotation.Order;
    12. import org.springframework.http.codec.ServerCodecConfigurer;
    13. import org.springframework.web.reactive.result.view.ViewResolver;
    14. import java.util.Collections;
    15. import java.util.List;
    16. //覆盖默认的异常处理
    17. @Configuration
    18. @EnableConfigurationProperties({ServerProperties.class, ResourceProperties.class})
    19. public class ErrorHandlerConfig {
    20. private final ServerProperties serverProperties;
    21. private final ApplicationContext applicationContext;
    22. private final ResourceProperties resourceProperties;
    23. private final List viewResolvers;
    24. private final ServerCodecConfigurer serverCodecConfigurer;
    25. public ErrorHandlerConfig(ServerProperties serverProperties,
    26. ResourceProperties resourceProperties,
    27. ObjectProvider> viewResolversProvider,
    28. ServerCodecConfigurer serverCodecConfigurer,
    29. ApplicationContext applicationContext) {
    30. this.serverProperties = serverProperties;
    31. this.applicationContext = applicationContext;
    32. this.resourceProperties = resourceProperties;
    33. this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);
    34. this.serverCodecConfigurer = serverCodecConfigurer;
    35. }
    36. @Bean
    37. @Order(Ordered.HIGHEST_PRECEDENCE)
    38. public ErrorWebExceptionHandler errorWebExceptionHandler(ErrorAttributes errorAttributes) {
    39. JsonExceptionHandler exceptionHandler = new JsonExceptionHandler(
    40. errorAttributes,
    41. this.resourceProperties,
    42. this.serverProperties.getError(),
    43. this.applicationContext);
    44. exceptionHandler.setViewResolvers(this.viewResolvers);
    45. exceptionHandler.setMessageWriters(this.serverCodecConfigurer.getWriters());
    46. exceptionHandler.setMessageReaders(this.serverCodecConfigurer.getReaders());
    47. return exceptionHandler;
    48. }
    49. }

    跨域:

    由于 gateway 使⽤的是 webflux ,⽽不是 springmvc ,所以需要先关闭 springmvc cors ,再从gateway filter ⾥边设置 cors 就⾏了。
    1. import org.springframework.context.annotation.Bean;
    2. import org.springframework.context.annotation.Configuration;
    3. import org.springframework.web.cors.CorsConfiguration;
    4. import org.springframework.web.cors.reactive.CorsWebFilter;
    5. import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource;
    6. import org.springframework.web.util.pattern.PathPatternParser;
    7. @Configuration
    8. public class CorsConfig {
    9. //处理跨域
    10. @Bean
    11. public CorsWebFilter corsFilter() {
    12. CorsConfiguration config = new CorsConfiguration();
    13. config.addAllowedMethod("*");
    14. config.addAllowedOrigin("*");
    15. config.addAllowedHeader("*");
    16. UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(new PathPatternParser());
    17. source.registerCorsConfiguration("/**", config);
    18. return new CorsWebFilter(source);
    19. }
    20. }

  • 相关阅读:
    Lwip中实现DM9000/DM9003驱动之一
    AD9371 官方例程HDL详解之JESD204B TX侧时钟生成 (三)
    EMC VNX支持数据文件说明
    CI/CD——Jenkins自动构建maven项目
    Chapter13 : Ultrahigh Throughput Protein-Ligand Docking with Deep Learning
    Flutter关于StatefulWidget中State刷新时机的一点实用理解
    Vue----数据源中数组的操作
    Java开发中遇到最难的问题,轻松获得一线大厂面试offer
    微信小程序数据存储方式有哪些
    CVE-2023-5129:libwebp开源库10分漏洞
  • 原文地址:https://blog.csdn.net/xushuai2333333/article/details/128084987