栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

springcloud ali gateway介绍

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

springcloud ali gateway介绍

一:Gateway简介

文档:Spring Cloud Gateway

小结:

nacos :注册中心,解决服务的注册与发现

Ribbon:客户端负载均衡器,解决微服务集群负载均衡的问题

Openfeign:声明式HTTP客户端,解决微服务之间远程调用问题

Sentinel:微服务流量防卫兵,以流量为入口,保护微服务,防止出现服务雪崩.

1.0:为什么使用网关

 

1.1:什么是Springcloud-gateway

 

1:springcloud-gateway是第二代网关,取代zuul

2:springcloud-gateway是基于 Spring Boot 2.x, Spring WebFlux和Project Reactor 构建的。netty服务器运行

3:是微服务的统一入口

1.2:Springcloud-gateway特点

1:性能强劲(是zuul1.x的1.6倍)

2:功能强大(转发、监控、限流)

1.3:gateway核心概念

 

  • Route(路由)

路由是构建网关的基本模块,它由ID,目标URI,一系列的断言和过滤器组成,如果断言为true则匹配该路由
  • Predicate(断言、谓词)

开发人员可以匹配HTTP请求中的所有内容(例如请求头或请求参数),如果请求与断言相匹配则进行路由
  • Filter(过滤)

指的是Spring框架中GatewayFilter的实例,使用过滤器,可以在请求被路由前或者之后对请求进行修改

1.4:gateway的工作流程
1:客户端向 Spring Cloud Gateway 发出请求。然后在 Gateway Handler Mapping 中找到与请求相匹配的路由
2:将其发送到 Gateway Web Handler。
3:Handler 再通过指 定的过滤器链来将请求发送到我们实际的服务执行业务逻辑,然后返回。过滤器之间用虚线分开是因为过滤器可能会在发送代理请求之前(“pre”)或之后(“post”)执行业务逻辑。

 

1.5:搭建网关wfx-gateway 1.5.1:pom依赖

注意:不要依赖spring-boot-starter-web


    org.springframework.boot
    
    spring-boot-starter-web

依赖如下:

 
        
        
            org.springframework.cloud
            spring-cloud-starter-gateway
        
      
        
            org.springframework.boot
            spring-boot-starter-actuator
        
​
        
        
            com.alibaba.cloud
            spring-cloud-starter-alibaba-nacos-discovery
        
    

1.5.2:基本配置

配置文件采用yml

server:
  #gateway的端口
  port: 8040
​
spring:
  application:
    name: wfx-gateway
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848

1.5.3:引导类
package com.wfx;
​
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
​

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

二:路由配置姿势 2.1:路由到指定URL
spring:
  cloud:
    gateway:
      routes:
        - id: baidu
          uri: http://www.baidu.com
          predicates:
            - Path=
@Component
public class MyHeaderRoutePredicateFactory extends AbstractRoutePredicateFactory {
    public MyHeaderRoutePredicateFactory() {
        super(MyConfig.class);
    }
​
    @Override
    public Predicate apply(MyConfig config) {
​
​
​
        return new Predicate() {
            @Override
            public boolean test(ServerWebExchange exchange) {
​
                //获取请求头
                //需求:请求头中必须要有 指定的kv 键值对
//                String value = exchange.getRequest().getHeaders().getFirst(config.getKey());
//                if (value == null) {
//
//                    return false;
//                }else{
//                    if(value.equals(config.getValue())){
//                        return true;
//                    }else{
//                        return  false;
//                    }
//                }
​
​
​
                if(StringUtils.isEmpty(config.getValue())){//只配置了key,但是没有配置value
​
                    if(exchange.getRequest().getHeaders().containsKey(config.getKey())){
                        return true;
                    }else{
                        return  false;
                    }
​
​
                }else{//同时配置了key和value
​
                    //根据key获取value
                    String value = exchange.getRequest().getHeaders().getFirst(config.getKey());
                    if(config.getValue().equals(value)){
                           return  true;
                    }else{
                        return  false;
                    }
​
                }
​
​
​
​
​
            }
        };
    }
​
    //获取配置参数
    @Override
    public List shortcutFieldOrder() {
​
​
        //- MyHeader=bbb,cccc
        //[bbb,cccc]
        //bbb赋值给MyConfig#key
        //cccc赋值给MyConfig#value
​
        return Arrays.asList("key","value");
    }
}

server:
  #网关微服务的启动端口
  port: 8040
spring:
  application:
    name: wfx-gateway #微服务的应用名
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848 #nacos-server的服务地址
    gateway:
      #配置路由规则
      routes:
        - id: wfx-goods
          #请求转发到微服务集群
          uri: lb://wfx-goods
          predicates:
            - Path=/goods
@Component
public class CalServiceTimeGatewayFilterFactory extends AbstractNameValueGatewayFilterFactory {
    @Override
    public GatewayFilter apply(NameValueConfig config) {
​
​
​
        return new GatewayFilter() {
            @Override
            public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
                //前处理
                long startTime = System.currentTimeMillis();
​
                System.out.println("name:"+config.getName());
                System.out.println("value:"+config.getValue());
​
​
//                return chain.filter(exchange);//放行
​
                return  chain.filter(exchange).then(
                    //后置处理
                    Mono.fromRunnable(()->{
                        System.out.println("post come in");
                        //获取系统当前时间戳为endTime
                        long entTime = System.currentTimeMillis();
                        System.out.println("time="+(entTime-startTime));
​
                    }));
            }
        };
    }
​
    @Override
    public ShortcutType shortcutType() {
        return ShortcutType.DEFAULT;
    }
}

server:
  #网关微服务的启动端口
  port: 8040
spring:
  application:
    name: wfx-gateway #微服务的应用名
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848 #nacos-server的服务地址
    gateway:
      #配置路由规则
      routes:
        - id: wfx-goods
          #请求转发到微服务集群
          uri: lb://wfx-goods
          predicates:
            - Path=/goods
@Component
public class AuthFilter implements GlobalFilter, Ordered {
    @Override
    public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
​
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();
​
​
        //获取jwt令牌
        String jwtToken = exchange.getRequest().getHeaders().getFirst("token");
        if (jwtToken == null) {
​
            //不能放行,直接返回,返回json信息
            response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
​
            Map res = new HashMap(){{
                put("success",false);
                put("msg","必须指定token");
            }};
​
            ObjectMapper objectMapper = new ObjectMapper();
            String jsonStr = null;
            try {
                jsonStr = objectMapper.writeValueAsString(res);
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
​
​
            DataBuffer dataBuffer = response.bufferFactory().wrap(jsonStr.getBytes());
​
            return response.writeWith(Flux.just(dataBuffer));//响应json数据
​
​
        }else{
            //校验令牌
           if( jwtToken.equals("xx")){//校验成功
              return   chain.filter(exchange);  //放行
           }else{
​
               //不能放行,直接返回,返回json信息
               response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
​
               Map res = new HashMap(){{
                   put("success",false);
                   put("msg","令牌不合法");
               }};
​
               ObjectMapper objectMapper = new ObjectMapper();
               String jsonStr = null;
               try {
                   jsonStr = objectMapper.writeValueAsString(res);
               } catch (JsonProcessingException e) {
                   e.printStackTrace();
               }
​
​
               DataBuffer dataBuffer = response.bufferFactory().wrap(jsonStr.getBytes());
​
               return response.writeWith(Flux.just(dataBuffer));//响应json数据
           }
        }
​
​
    }
​
​
    //指定过滤器的执行顺序,值越小越先执行
    @Override
    public int getOrder() {
        return 0;
    }
}

package com.wfx;
​
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.core.annotation.Order;
import reactor.core.publisher.Mono;
​
import java.time.ZonedDateTime;
​

@SpringBootApplication
@EnableDiscoveryClient
public class WfxGateway {
​
    public static void main(String[] args) {
        SpringApplication.run(WfxGateway.class,args);
​
    }
    
    @Bean
    @Order(1)
    public GlobalFilter  aFilter(){
​
        return  new GlobalFilter() {
            @Override
            public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
​
                System.out.println("A come in ");
​
​
                return chain.filter(exchange).then(   Mono.fromRunnable(()->{
                    System.out.println("A post come in");
​
                }));
            }
        };
    }
​
​
    @Bean
    @Order(2)
    public GlobalFilter  bFilter(){
​
        return  new GlobalFilter() {
            @Override
            public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
​
                System.out.println("b come in ");
​
​
                return chain.filter(exchange).then(   Mono.fromRunnable(()->{
                    System.out.println("b post come in");
​
                }));
            }
        };
    }
​
    @Bean
    @Order(-1)
    public GlobalFilter a() {
        return (exchange, chain) -> {
            System.out.println("first pre filter");
            return chain.filter(exchange).then(Mono.fromRunnable(() -> {
                System.out.println("third post filter");
            }));
        };
    }
​
    @Bean
    @Order(0)
    public GlobalFilter b() {
        return (exchange, chain) -> {
            System.out.println("second pre filter");
            return chain.filter(exchange).then(Mono.fromRunnable(() -> {
                System.out.println("second post filter");
            }));
        };
    }
​
    @Bean
    @Order(1)
    public GlobalFilter c() {
        return (exchange, chain) -> {
            System.out.println("third pre filter");
            return chain.filter(exchange).then(Mono.fromRunnable(() -> {
                System.out.println("first post filter");
            }));
        };
    }
​
​
}

五:gateway整合sentinel

Sentinel从 1.6.0 版本开始提供了 Spring Cloud Gateway 的适配模块,可以提供两种资源维度的限流:

  • route 维度:即在 Spring 配置文件中配置的路由条目,资源名为对应的 routeId自定义

  • API 维度:用户可以利用 Sentinel 提供的 API 来自定义一些 API 分组

5.1:整合步骤

第一步:pom依赖


    com.alibaba.cloud
    spring-cloud-starter-alibaba-sentinel


    com.alibaba.csp
    sentinel-spring-cloud-gateway-adapter

第二步:配置

spring:
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
    sentinel:
      transport:
        dashboard: 127.0.0.1:8888
        port: 8710

5.2:BlockException异常处理

默认BlockException异常全局处理器 SentinelGatewayBlockExceptionHandler

package com.wfx.config;
​
import com.alibaba.csp.sentinel.adapter.gateway.sc.SentinelGatewayFilter;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.web.reactive.result.view.ViewResolver;
​
import java.util.Collections;
import java.util.List;
​
@Configuration
public class GatewayConfiguration {
​
    private final List viewResolvers;
    private final ServerCodecConfigurer serverCodecConfigurer;
​
    public GatewayConfiguration(ObjectProvider> viewResolversProvider,
                                ServerCodecConfigurer serverCodecConfigurer) {
        this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);
        this.serverCodecConfigurer = serverCodecConfigurer;
    }
​
    @Bean
    //order不能为-1  必须优先级最高
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
        // Register the block exception handler for Spring Cloud Gateway.
        return new SentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);
    }
​
    @Bean
    public GlobalFilter sentinelGatewayFilter() {
        // By default the order is HIGHEST_PRECEDENCE
        return new SentinelGatewayFilter();
    }
}

自定义BlockException异常处理器

package com.wfx.sentinel;
​
import com.alibaba.csp.sentinel.adapter.gateway.sc.SentinelGatewayFilter;
import com.alibaba.csp.sentinel.adapter.gateway.sc.exception.SentinelGatewayBlockExceptionHandler;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.web.reactive.result.view.ViewResolver;
​
import java.util.Collections;
import java.util.List;
​
@Configuration
public class GatewayConfiguration {
​
    private final List viewResolvers;
    private final ServerCodecConfigurer serverCodecConfigurer;
​
    public GatewayConfiguration(ObjectProvider> viewResolversProvider,
                                ServerCodecConfigurer serverCodecConfigurer) {
        this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);
        this.serverCodecConfigurer = serverCodecConfigurer;
    }
​
    @Bean
    // 必须优先级最高
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public MySentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
        // Register the block exception handler for Spring Cloud Gateway.
        return new MySentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);
    }
​
    @Bean
    public GlobalFilter sentinelGatewayFilter() {
        // By default the order is HIGHEST_PRECEDENCE
        return new SentinelGatewayFilter();
    }
}

package com.wfx.sentinel;
​
import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.GatewayCallbackManager;
import com.alibaba.csp.sentinel.adapter.gateway.sc.exception.SentinelGatewayBlockExceptionHandler;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.util.function.Supplier;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.codec.HttpMessageWriter;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.reactive.function.server.ServerResponse;
import org.springframework.web.reactive.result.view.ViewResolver;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebExceptionHandler;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
​
import java.util.HashMap;
import java.util.List;
import java.util.Map;
​

​
public class MySentinelGatewayBlockExceptionHandler  implements WebExceptionHandler {
    private List viewResolvers;
    private List> messageWriters;
    private final Supplier contextSupplier = () -> {
        return new ServerResponse.Context() {
            public List> messageWriters() {
                return MySentinelGatewayBlockExceptionHandler.this.messageWriters;
            }
​
            public List viewResolvers() {
                return MySentinelGatewayBlockExceptionHandler.this.viewResolvers;
            }
        };
    };
​
    public MySentinelGatewayBlockExceptionHandler(List viewResolvers, ServerCodecConfigurer serverCodecConfigurer) {
        this.viewResolvers = viewResolvers;
        this.messageWriters = serverCodecConfigurer.getWriters();
    }
​
​
    //自定义异常处理
    private Mono writeResponse(ServerResponse response1, ServerWebExchange exchange) {
​
        ServerHttpResponse response = exchange.getResponse();
​
        //不能放行,直接返回,返回json信息
        response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
​
        Map res = new HashMap(){{
            put("success",false);
            put("msg","系统繁忙,请稍后重试!!");
        }};
​
        ObjectMapper objectMapper = new ObjectMapper();
        String jsonStr = null;
        try {
            jsonStr = objectMapper.writeValueAsString(res);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
​
​
        DataBuffer dataBuffer = response.bufferFactory().wrap(jsonStr.getBytes());
​
        return response.writeWith(Flux.just(dataBuffer));//响应json数据
​
    }
​
    public Mono handle(ServerWebExchange exchange, Throwable ex) {
        if (exchange.getResponse().isCommitted()) {
            return Mono.error(ex);
        } else {
            return !BlockException.isBlockException(ex) ? Mono.error(ex) : this.handleBlockedRequest(exchange, ex).flatMap((response) -> {
                return this.writeResponse(response, exchange);
            });
        }
    }
​
    private Mono handleBlockedRequest(ServerWebExchange exchange, Throwable throwable) {
        return GatewayCallbackManager.getBlockHandler().handleRequest(exchange, throwable);
    }
}

六:gateway跨域

由于gateway使用的是webflux,而不是springmvc,所以需要先关闭springmvc的cors,再从gateway的filter里边设置cors就行了。

​
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.reactive.CorsWebFilter;
import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource;
import org.springframework.web.util.pattern.PathPatternParser;
​
@Configuration
public class CorsConfig {
    @Bean
    public CorsWebFilter corsFilter() {
        CorsConfiguration config = new CorsConfiguration();
        config.addAllowedMethod("*");
        config.addAllowedOrigin("*");
        config.addAllowedHeader("*");
​
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(new PathPatternParser());
        source.registerCorsConfiguration("/**", config);
​
        return new CorsWebFilter(source);
    }
}

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1013666.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号