【无标题】

网关:统一的入口

  • 请求路由的转发
  • 负载均衡
  • 流量控制,,, sentinel可以融入网关,对全局qps做统一限流
  • 身份认证
  • 协议转换 : 前段发过来的是json,,但是后端远程调用的协议用的别的协议,,就需要将json转换成适配的数据
  • 系统监控
  • 安全防护

spring cloud gateway 有两个版本的网关,,一般都使用响应式网关spring-cloud-starter-gateway

网关不属于业务,,属于架构的一部分

spring cloud gateway

spring cloud gateway里面可以配置多个路由规则,,每个路由规则都是自己的 predicate断言,,filter过滤器,uri:目的地,,,
RouteDefinition : 路由定义的类

  • id
  • uri
  • predicates :PredicateDefinition
  • filters : FilterDefinition

GatewayHandlerMapping : 请求映射,,,知道某些规则要转给哪里,,但是怎么转过去,需要GatewayWebHandler去处理,,可能处理链路上,有多个过滤器

自定义断言

每一个路由规则的断言和过滤器,,都是通过工厂去创建的,,
AbstractRoutePredicateFactory这个下面有很多的实现类,,就是实现的路由规则

gateway内置了很多断言的规则:

也可以自己集成这个抽象类,去实现自定义的断言规则,,断言的名字和类名的前面几个字母一致,,,

yml 复制代码
spring:
  cloud:
    gateway:
      routes:
        - id: bing-route
          uri: https://cn.bing.com
          predicates:
            - name: Path
              args:
                pattern: /search
            - name: Query
              args:
                param: q
                regexp: haha
                # 使用vip这个断言器
#            - Vip=ser,waterkid
            - name: Vip
              # Config里面配置的参数  http://localhost/search?q=haha&user=waterkid
              args:
                param: user
                value: waterkid

自定义名字叫Vip的规则:

java 复制代码
package com.cj.predicate;

import org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory;
import org.springframework.cloud.gateway.handler.predicate.GatewayPredicate;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;

import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;

/**
 * 这个泛型 是 当前工厂的配置
 */
@Component
public class VipRoutePredicateFactory extends AbstractRoutePredicateFactory<VipRoutePredicateFactory.Config> {


    public VipRoutePredicateFactory() {
        super(Config.class);
    }

    @Override
    public List<String> shortcutFieldOrder() {
        // 参数的字段排序,,,, 第一个参数映射到 Config的param,,第二个参数映射到 Config的regexp中
        return Arrays.asList("param","value");
    }

    @Override
    public Predicate<ServerWebExchange> apply(Config config) {
        return new GatewayPredicate() {
            @Override
            public boolean test(ServerWebExchange serverWebExchange) {
                // ServerWebExchange 里面封装了请求和响应
                // 是否转发
                ServerHttpRequest request = serverWebExchange.getRequest();
                MultiValueMap<String, String> queryParams = request.getQueryParams();

                String first = queryParams.getFirst(config.param);
                // 参数有值,,并且配置的值和传入的值一样
                if (StringUtils.hasText(first) && first.equals(config.value)){

                    return true;
                }
                return false;
            }
        };
    }

    /**
     * 可以配置的参数
     */
    public static class Config{
        private String param;

        private String value;


        public String getParam() {
            return param;
        }

        public void setParam(String param) {
            this.param = param;
        }

        public String getValue() {
            return value;
        }

        public void setValue(String value) {
            this.value = value;
        }
    }
}

断言规则:

过滤器

gateway也内置了很多过滤器,,过滤器也是通过工厂去创建的

自定义网关过滤器

自定义一个携带token响应头的后置过滤:

java 复制代码
package com.cj.filter;

import org.apache.http.nio.pool.NIOConnFactory;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.factory.AbstractNameValueGatewayFilterFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.UUID;

/**
 * AbstractNameValueGatewayFilterFactory: 能传递两个参数  name 和 value
 */
@Component
public class OnceTokenGatewayFilterFactory extends AbstractNameValueGatewayFilterFactory {
    @Override
    public GatewayFilter apply(NameValueConfig config) {
        return new GatewayFilter() {
            @Override
            public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
                // 每次响应之前,,添加一个一次性令牌
                return chain.filter(exchange).then(Mono.fromRunnable(() -> {
                    ServerHttpResponse response = exchange.getResponse();
                    HttpHeaders headers = response.getHeaders();
                    String name = config.getName();
                    String value = config.getValue();
                    if (value.equalsIgnoreCase("uuid")) {
                        value = UUID.randomUUID().toString();
                    }

                    if ("jwt".equalsIgnoreCase(value)) {
                        value = "jwtToken";
                    }

                    headers.add(name, value);

                }));
            }
        };
    }
}
yml 复制代码
spring:
  cloud:
    gateway:
      routes:
        - id: order-route
          # load balancer .转到 order---service
          uri: lb://service-order
          # 满足规则转发  ,,, 这里转过去了之后,,订单服务会找一模一样的 uri,,就会404
          predicates:
            - name: Path
              args:
                patterns: /api/order/**
                # 允许尾部url多一个 /
                matchTrailingSlash: true
          filters:
            # 路径重写
            - RewritePath=/api/order/?(?<segment>.*),/$\{segment}
            # 添加响应头
            - AddResponseHeader=X-Response-abc,123
            # 自定义过滤器
            - OnceToken=X-Response-Token,uuid
自定义全局过滤器: 对所有请求都生效
java 复制代码
package com.cj.filter;

import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

/**
 * 全局filter
 * response time  :
 */
@Component
@Slf4j
public class RtGlobalFilter implements GlobalFilter, Ordered {
    /**
     *
     * @param exchange 这里面封装了 请求和响应的对象
     * @param chain provides a way to delegate to the next filter
     * @return
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();

        String uri = request.getURI().toString();

        long start = System.currentTimeMillis();
        log.info("请求{} 开始,时间为:{}",uri,start);


//        // 响应式编程,,是全异步逻辑
//        Mono<Void> filter = chain.filter(exchange)// 异步放行,,下面的代码,,不会等待这个放行结束
//                .doFinally((result)->{
//                    // 在这里写放行结束的逻辑
//                    long end = System.currentTimeMillis();
//                    log.info("请求{} 结束,时间为:{}",uri,end-start);
//                });

        // 响应式编程,,是全异步逻辑
        Mono<Void> filter = chain.filter(exchange);// 异步放行,,下面的代码,,不会等待这个放行结束

        // doFinally会返回新的Mono,,
        Mono<Void> newFilter = filter.doFinally((result) -> {
            // 在这里写放行结束的逻辑
            long end = System.currentTimeMillis();
            log.info("请求{} 结束,时间为:{}", uri, end - start);
        });

        return newFilter;
    }

    @Override
    public int getOrder() {
        return 0;
    }
}
gateway跨域

跨域的本质,,就是服务端返回浏览器要求的指定cors响应头,,让浏览器放行原本被同源策略拦截的跨域请求

浏览器为了安全,制定了同源策略,,,不同源的请求,,浏览器会拦截响应,,除非服务端明确,允许跨域的响应头,浏览器才会放行

gateway配置跨域:

yml 复制代码
spring:
  cloud:
    gateway:
      globalcors:
        cors-configurations:
          '[/**]':
            allowed-origin-patterns: '*'
            allowed-headers: '*'
            allowed-methods: '*'
相关推荐
Rain的Java大神之路11 小时前
如何快速上传10G文件
java·spring boot·redis·后端·mysql·spring cloud·面试
需要82615 小时前
MySQL 索引 B+ 树与“查询为什么变慢了
java·spring boot·spring·spring cloud·tomcat
需要82619 小时前
Arthas 一个命令排查线上问题
java·jvm·spring·spring cloud
苏渡苇2 天前
Spring Insight 里如何把 Span 画成瀑布时间线
后端·spring·spring cloud·springboot·监控·apm
叶总没有会2 天前
Nacos—注册中心
spring cloud·微服务
苏渡苇3 天前
Spring Insight 里如何把 Span 收成一条链路
spring boot·spring·spring cloud·系统监控·apm
叶总没有会3 天前
微服务--分布式基础
java·spring·spring cloud·微服务
孙启超4 天前
【AI开发之Rust】第 7 课:错误处理 —— panic、Result 与 `?`
人工智能·分布式·后端·爬虫·spring cloud·架构·rust
行百里er5 天前
Spring Insight 里如何把 Span 收成一条链路
spring boot·spring cloud·监控
砍材农夫5 天前
spring|spring web|拦截器、过滤器、aop
java·spring boot·spring·spring cloud