微服务(四)——统一网关

喜欢ヅ旅行 2023-09-25 14:19 123阅读 0赞

目录

    1. 概念
    1. 实现网关
      1. 实现流程
      1. 小结
    1. 断言工厂
    1. 过滤器工厂
      1. GatewayFilter
      1. GlobalFilter
      1. 过滤器的执行顺序
    1. 解决跨域问题

1. 概念

网关的作用:

d7889ea4aa8241b0bd9e1729b899942a.png4e55012cdcfb4a62868b5686737dd53e.pngb7d1e24e2e8843e8b382368cd9725cab.png

  • 认证、鉴权
  • 服务路由、负载均衡
  • 请求限流

网关的实现:

  • gateway
    基于Spring5中提供的WebFlux,属于响应式编程的实现,具备更好的性能
  • zuul
    基于Servlet的实现,属于阻塞式编程

2. 实现网关

1. 实现流程

新建module:
04ec47750a614ca1949c82cb19dad169.png

引入依赖:

  1. <!--网关-->
  2. <dependency>
  3. <groupId>org.springframework.cloud</groupId>
  4. <artifactId>spring-cloud-starter-gateway</artifactId>
  5. </dependency>
  6. <!--nacos服务发现依赖-->
  7. <dependency>
  8. <groupId>com.alibaba.cloud</groupId>
  9. <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
  10. </dependency>

启动类:

  1. @SpringBootApplication
  2. public class GatewayApplication {
  3. public static void main(String[] args) {
  4. SpringApplication.run(GatewayApplication.class, args);
  5. }
  6. }

配置文件:

  1. # 配置nacos服务地址
  2. server:
  3. port: 8099 # 网关端口
  4. spring:
  5. application:
  6. name: gateway # 服务名称
  7. cloud:
  8. nacos:
  9. server-addr: localhost:8848 # nacos地址
  10. gateway:
  11. routes: # 网关路由配置
  12. - id: gateway # 路由id,自定义,只要唯一即可
  13. # uri: http://127.0.0.1:8081 # 路由的目标地址 http就是固定地址
  14. uri: lb://provider # 路由的目标地址 lb就是负载均衡,后面跟服务名称
  15. predicates: # 路由断言,也就是判断请求是否符合路由规则的条件
  16. - Path=/pro/** # 这个是按照路径匹配,只要以/pro/开头就符合要求

启动报错:

  1. Parameter 0 of method loadBalancerWebClientBuilderBeanPostProcessor in org.springframework.cloud.client.loadbalancer.reactive.LoadBalancerBeanPostProcessorAutoConfiguration required a bean of type 'org.springframework.cloud.client.loadbalancer.reactive.DeferringLoadBalancerExchangeFilterFunction' that could not be found.

解决报错:引入 loadbalancer 依赖

  1. <!--loadbalancer——防止报错-->
  2. <dependency>
  3. <groupId>org.springframework.cloud</groupId>
  4. <artifactId>spring-cloud-starter-loadbalancer</artifactId>
  5. </dependency>

访问测试:
0e67478ff7464735b2278c279989763c.png

2. 小结

网关访问流程:
3894a9782563499e9f1be2190b122e7b.png

  • id:自定义,网关唯一标识
  • uri:使用负载均衡+服务名作为路由地址(lb://serviceName
  • predicates:路由断言,满足断言匹配规则才能进行访问

3. 断言工厂

在配置文件中的 gateway.routes.predicates 中定义好匹配规则,然后这些规则就会被 断言工厂(predicate factory——org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory) 读取并处理,转换为路由判断的条件。

常见断言工厂:


































































名称 说明 示例
After 是某个时间点后的请求 - After=2037-01-20T17:42:47.789-07:00[America/Denver]
Before 是某个时间点之前的请求 - Before=2031-04-13T15:14:47.433+08:00[Asia/Shanghai]
Between 是某两个时间点之前的请求 - Between=2037-01-20T17:42:47.789-07:00[America/Denver], 2037-01-21T17:42:47.789-07:00[America/Denver]
Cookie 请求必须包含某些cookie - Cookie=chocolate, ch.p
Header 请求必须包含某些header - Header=X-Request-Id, \d+
Host 请求必须是访问某个host(域名) - Host=.somehost.org,.anotherhost.org
Method 请求方式必须是指定方式 - Method=GET,POST
Path 请求路径必须符合指定规则 - Path=/red/{segment},/blue/**
Query 请求参数必须包含指定参数 - Query=name, Jack或者- Query=name
RemoteAddr 请求者的ip必须是指定范围 - RemoteAddr=192.168.1.1/24
Weight 权重处理

断言工厂官方写法: https://docs.spring.io/spring-cloud-gateway/docs/3.1.4/reference/html/#gateway-request-predicates-factories

注意: 可同时匹配多个断言规则。

4. 过滤器工厂

1. GatewayFilter

过滤器(GatewayFilter)可以对进入网关的请求和微服务返回的响应做处理。
f887586700cc4ea3b6c4dcd24fe3929d.png

常见过滤器:






























名称 说明
AddRequestHeader 给当前请求添加一个请求头
RemoveRequestHeader 移除请求中的一个请求头
AddResponseHeader 给响应结果中添加一个响应头
RemoveResponseHeader 从响应结果中移除有一个响应头
RequestRateLimiter 限制请求的流量

过滤器官方写法: https://docs.spring.io/spring-cloud-gateway/docs/3.1.4/reference/html/#gatewayfilter-factories

指定服务,过滤器仅对 provider 服务生效:

  1. gateway:
  2. routes: # 网关路由配置
  3. - id: gatewayid # 路由id,自定义,只要唯一即可
  4. # uri: http://127.0.0.1:8081 # 路由的目标地址 http就是固定地址
  5. uri: lb://provider # 路由的目标地址 lb就是负载均衡,后面跟服务名称
  6. predicates: # 路由断言,也就是判断请求是否符合路由规则的条件
  7. - Path=/pro/** # 这个是按照路径匹配,只要以/pro/开头就符合要求
  8. # 将标头添加到所有匹配请求的下游请求标头中。X-Request-red:blue
  9. filters:
  10. - AddRequestHeader=X-Request-red, blue

默认过滤器,对所有服务都生效:

  1. gateway:
  2. routes: # 网关路由配置
  3. - id: gatewayid # 路由id,自定义,只要唯一即可
  4. # uri: http://127.0.0.1:8081 # 路由的目标地址 http就是固定地址
  5. uri: lb://provider # 路由的目标地址 lb就是负载均衡,后面跟服务名称
  6. predicates: # 路由断言,也就是判断请求是否符合路由规则的条件
  7. - Path=/pro/** # 这个是按照路径匹配,只要以/pro/开头就符合要求
  8. default-filters:
  9. - AddRequestHeader=X-Request-red, blue

2. GlobalFilter

全局过滤器(GlobalFilter): 处理一切进入网关的请求和微服务响应,不同于 GatewayFilter ,全局过滤器需要自己写代码实现过滤逻辑。

自定义的全局过滤器需要实现以下接口

  1. public interface GlobalFilter {
  2. /**
  3. * 处理Web请求、委托给下一个下一个过滤器处理(可选)
  4. * @param exchange 请求上下文,里面可以获取Request、Response等信息
  5. * @param chain 用来把请求委托给下一个过滤器
  6. * @return {@code Mono<Void>} 返回标示当前过滤器业务结束
  7. */
  8. Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain);
  9. }

可通过实现上述接口,重写 filter 方法实现以下功能:

  • 登录状态判断
  • 权限校验
  • 请求限流

实现身份认证:

  1. @Order(-100)
  2. @Component
  3. public class AuthorizeFilter implements GlobalFilter {
  4. @Override
  5. public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
  6. // 1.获取请求参数
  7. ServerHttpRequest request = exchange.getRequest();
  8. MultiValueMap<String, String> params = request.getQueryParams();
  9. // 2.获取参数中的 auth 参数
  10. String auth = params.getFirst("auth");
  11. // 3.判断参数值是否等于 root
  12. if ("root".equals(auth)) {
  13. // 4.是,放行
  14. return chain.filter(exchange);
  15. }
  16. // 5.否,拦截
  17. // 5.1.设置状态码
  18. exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
  19. // 5.2.拦截请求
  20. return exchange.getResponse().setComplete();
  21. }
  22. }
  • @Order 用来处理相同接口实现类的执行优先级问题

    • 数值越小,越优先执行

测试:

d11c7d3df67b4831b8581669b13cfd5a.png4e55012cdcfb4a62868b5686737dd53e.pngb370cbfaca3141449caaa7c83b737289.png

3. 过滤器的执行顺序

默认执行顺序如下:
adb4c220e0ee4573a761d74e2c7481c5.png

  • 每个过滤器都被指定了一个整型的 order 值,order 越小,优先级越高,越早执行
  • 路由过滤器(单个微服务的)和 默认过滤器 的 order 值 由 spring 指定,全局过滤器的 order 需要自行指定

5. 解决跨域问题

跨域问题:

  • 跨域:域名不一致,包括三种类型:①域名不同;②域名相同,端口不同;③ 二级域名不同
  • 跨域问题:浏览器禁止请求的发起者与服务端发生跨域ajax请求,请求被浏览器拦截的问题

解决跨域问题:

  • 方式一: CORS
    跨域问题及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.UrlBasedCorsConfigurationSource;
    5. import org.springframework.web.filter.CorsFilter;
    6. @Configuration
    7. public class GlobalCorsConfig {
  1. @Bean
  2. public CorsFilter corsFilter() {
  3. //1.添加CORS配置信息
  4. CorsConfiguration config = new CorsConfiguration();
  5. //1) 允许的域,不要写*,否则cookie就无法使用了
  6. config.addAllowedOrigin("http://manage.leyou.com");
  7. //2) 是否发送Cookie信息
  8. config.setAllowCredentials(true);
  9. //3) 允许的请求方式
  10. config.addAllowedMethod("OPTIONS");
  11. config.addAllowedMethod("HEAD");
  12. config.addAllowedMethod("GET");
  13. config.addAllowedMethod("PUT");
  14. config.addAllowedMethod("POST");
  15. config.addAllowedMethod("DELETE");
  16. config.addAllowedMethod("PATCH");
  17. // 4)允许的头信息
  18. config.addAllowedHeader("*");
  19. //2.添加映射路径,我们拦截一切请求
  20. UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource();
  21. configSource.registerCorsConfiguration("/**", config);
  22. //3.返回新的CorsFilter.
  23. return new CorsFilter(configSource);
  24. }
  25. }
  • 方式二:通过 gateway

    1. spring:
    2. cloud:
    3. gateway:
    4. # 。。。
    5. globalcors: # 全局的跨域处理
    6. add-to-simple-url-handler-mapping: true # 解决options请求被拦截问题
    7. corsConfigurations:
    8. '[/**]':
    9. allowedOrigins: # 允许哪些网站的跨域请求
    10. - "http://localhost:8090"
    11. allowedMethods: # 允许的跨域ajax的请求方式
    12. - "GET"
    13. - "POST"
    14. - "DELETE"
    15. - "PUT"
    16. - "OPTIONS"
    17. allowedHeaders: "*" # 允许在请求中携带的头信息
    18. allowCredentials: true # 是否允许携带cookie
    19. maxAge: 360000 # 这次跨域检测的有效期

发表评论

表情:
评论列表 (有 0 条评论,123人围观)

还没有评论,来说两句吧...

相关阅读

    相关 服务-GateWay()

    所谓网关是什么意思? 相当于就是你们小区家的保安,进出小区都得获得保安的同意,守护你们小区的生命财产健康,网关也是如此,对每个请求都严格把关,将合法的或者是获得权限的请求进入