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

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 # 这次跨域检测的有效期
    
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

364.99°

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值