小言_互联网的博客

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

390人阅读  评论(0)

1. 概念

网关的作用:

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

网关的实现:

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

2. 实现网关

1. 实现流程

新建module:

引入依赖:

        <!--网关-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
        <!--nacos服务发现依赖-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

启动类:

@SpringBootApplication
public class GatewayApplication {
   
    public static void main(String[] args) {
   
        SpringApplication.run(GatewayApplication.class, args);
    }
}

配置文件:

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

 

启动报错:

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 依赖

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

访问测试:

2. 小结

网关访问流程:

  • 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)可以对进入网关的请求和微服务返回的响应做处理。

常见过滤器:

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

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

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

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

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

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

2. GlobalFilter

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

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

public interface GlobalFilter {
   

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

}

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

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

实现身份认证:

@Order(-100)
@Component
public class AuthorizeFilter implements GlobalFilter {
   
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
   
        // 1.获取请求参数
        ServerHttpRequest request = exchange.getRequest();
        MultiValueMap<String, String> params = request.getQueryParams();
        // 2.获取参数中的 auth 参数
        String auth = params.getFirst("auth");
        // 3.判断参数值是否等于 root
        if ("root".equals(auth)) {
   
            // 4.是,放行
            return chain.filter(exchange);
        }
        // 5.否,拦截
        // 5.1.设置状态码
        exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
        // 5.2.拦截请求
        return exchange.getResponse().setComplete();
    }
}

 
  • @Order 用来处理相同接口实现类的执行优先级问题
    • 数值越小,越优先执行

测试:

3. 过滤器的执行顺序

默认执行顺序如下:

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

5. 解决跨域问题

跨域问题:

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

解决跨域问题:

  • 方式一: CORS
    跨域问题及CORS解决跨域问题方法

    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.cors.CorsConfiguration;
    import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
    import org.springframework.web.filter.CorsFilter;
    
    @Configuration
    public class GlobalCorsConfig {
         
       
        @Bean
        public CorsFilter corsFilter() {
         
       
            //1.添加CORS配置信息
            CorsConfiguration config = new CorsConfiguration();
            //1) 允许的域,不要写*,否则cookie就无法使用了
            config.addAllowedOrigin("http://manage.leyou.com");
            //2) 是否发送Cookie信息
            config.setAllowCredentials(true);
            //3) 允许的请求方式
            config.addAllowedMethod("OPTIONS");
            config.addAllowedMethod("HEAD");
            config.addAllowedMethod("GET");
            config.addAllowedMethod("PUT");
            config.addAllowedMethod("POST");
            config.addAllowedMethod("DELETE");
            config.addAllowedMethod("PATCH");
            // 4)允许的头信息
            config.addAllowedHeader("*");
    
            //2.添加映射路径,我们拦截一切请求
            UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource();
            configSource.registerCorsConfiguration("/**", config);
    
            //3.返回新的CorsFilter.
            return new CorsFilter(configSource);
        }
    }
    
       
  • 方式二:通过 gateway

    spring:
      cloud:
        gateway:
          # 。。。
          globalcors: # 全局的跨域处理
            add-to-simple-url-handler-mapping: true # 解决options请求被拦截问题
            corsConfigurations:
              '[/**]':
                allowedOrigins: # 允许哪些网站的跨域请求 
                  - "http://localhost:8090"
                allowedMethods: # 允许的跨域ajax的请求方式
                  - "GET"
                  - "POST"
                  - "DELETE"
                  - "PUT"
                  - "OPTIONS"
                allowedHeaders: "*" # 允许在请求中携带的头信息
                allowCredentials: true # 是否允许携带cookie
                maxAge: 360000 # 这次跨域检测的有效期
    
       

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