spring-cloud-gateway 入门使用

1. 基本介绍

网关开发中一般指的是: 应用的统一流量入口,负责转发请求到指定服务;

spring-cloud-gateway : 基于spring5.0, spring boot 2.0 , project reactor 等技术开发的网关,目的是为 微服务架构提供一种简单有效的统一的API路由管理方式;

1.1 通用网关功能

以下是网关的基本功能结构,围绕这几个点开始学习;

1.2 特有属性介绍

SpringCloud 官网介绍:

  1. 基于spring framework 5 , project reactor 和spring boot 2.0 ;

  2. 集成Hystrix 断路器 ;

  3. 集成 spring cloud discoveryClient (可以整合 eurake、ribbon, 实现负载均衡) ;

  4. predicate 和 filter 作用于特定路由,易于编写的 Predicates 和filters ;

  5. 具有一些网关的高级功能: 动态路由、限流、路径重写;

Predicate (断言)

java8的 predicate,可以用它来匹配 Http 请求的任何内容, 例如 headers 或参数,
断言的输入类型是一个 ServerWebExchange ;

Route (路由)

由一个跳转URI、一组predicate、一组Filter 组成的处理单元;

Filter(过滤器)

拦截和修改请求;

2. 入门使用

2.1 代码配置

以接口登录认证为例,我们实现一个简单的网关需求;

需求简单描述:

/login /send_code 等 这些不需要认证的接口 我们以配置的形式 体现;

其他接口,统一都需要认证;

注:header中含有user_token ,标识已登录

核心实现类:AuthGatewayFilterFactory

@Component
public class AuthGatewayFilterFactory extends AbstractGatewayFilterFactory<AuthGatewayFilterFactory.Config> {

    private Logger logger = LoggerFactory.getLogger(AuthGatewayFilterFactory.class);

    /**
     * 用户登录状态token
     */
    private static final String USER_TOKEN = "user_token";

    public AuthGatewayFilterFactory(){
        super(Config.class);
        logger.info("AuthGatewayFilterFactory init");
    }

    @Override
    public List<String> shortcutFieldOrder() {
        return Collections.singletonList("ignoreUrlListStr");
    }

    @Override
    public GatewayFilter apply(Config config) {
        return (exchange, chain) -> {
            ServerHttpRequest request = exchange.getRequest();
            // 校验是否是 不用登录的URL
            String path = request.getPath().toString();
            logger.info("AuthGatewayFilterFactory.apply path:{}",path);


            String ignoreUrlListStr = config.ignoreUrlListStr;
            logger.info("AuthGatewayFilterFactory.apply ignoreUrlListStr={}",ignoreUrlListStr);

            boolean ignoreOk = Arrays.asList(ignoreUrlListStr.split("\|")).contains(path);
            if(ignoreOk){
                return chain.filter(exchange);
            }

            // 校验是否登录
            HttpHeaders headers = request.getHeaders();
            String userToken = headers.getFirst(USER_TOKEN);
            if(StringUtils.isEmpty(userToken)){
                // 返回未登录提示
                ServerHttpResponse response = exchange.getResponse();
                response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
                response.setStatusCode(HttpStatus.UNAUTHORIZED);

                Map<String, Object> bodyMap = new HashMap<>();
                bodyMap.put("code",-1000003);
                bodyMap.put("message","未登录");

                byte[] responseByteArray = JSON.toJSONBytes(bodyMap);
                DataBuffer responseBuffer = response.bufferFactory().allocateBuffer(responseByteArray.length).write(responseByteArray);
                return response.writeWith(Mono.just(responseBuffer));
            }
            logger.info("AuthGatewayFilterFactory.apply  user-token={}",userToken);
            return chain.filter(exchange);
        };
    }

    public static class Config {
        private String ignoreUrlListStr;

        public String getIgnoreUrlListStr() {
            return ignoreUrlListStr;
        }

        public void setIgnoreUrlListStr(String ignoreUrlListStr) {
            this.ignoreUrlListStr = ignoreUrlListStr;
        }
    }
}
复制代码

application.properties 配置

# 网关配置 -- 免登录认证配置
spring.cloud.gateway.routes[0].id = login_auth
spring.cloud.gateway.routes[0].uri = https://www.baidu.com
spring.cloud.gateway.routes[0].predicates[0] = Path=/**
spring.cloud.gateway.routes[0].filters[0] = Auth=/login|/send_code
复制代码

以上配置解释如下:
定义一个路由:
名称:登录认证

跳转URL: 百度地址
断言: 拦截所有请求

过滤器: 除 /login ,/send_code 外 都进行拦截处理;

2.2 运行效果

非免检未登录

curl --location --request GET 'localhost:80/eat/apple'

{
    "code": -1000003,
    "message": "未登录"
}
复制代码

非免检已登录

curl --location --request GET 'localhost:80/eat/apple' \

--header 'user_token: 12138'

NOT FOUND
复制代码

免检接口

curl --location --request GET 'localhost:80/login'

Not Found
复制代码

3. 整合apollo

3.1 准备环境

首先准备apollo 环境,参见 apollo-sh 这个项目;

3.2 项目配置

pom.xml

<properties>
        <java.version>1.8</java.version>
        <lombok.version>1.18.10</lombok.version>
        <fastjson.version>1.2.78</fastjson.version>
        <spring-cloud-version>2.1.0.RELEASE</spring-cloud-version>
        <apollo-client.version>1.9.1</apollo-client.version>
</properties>

<dependency>
    <groupId>com.ctrip.framework.apollo</groupId>
    <artifactId>apollo-client</artifactId>
    <version>${apollo-client.version}</version>
</dependency>
复制代码

application.yml

# apollo 启动配置

app:
  id: yiyi-gateway
apollo:
  bootstrap:
    namespaces: application
    enabled: true
  meta: http://172.16.146.231:9001

ENV: DEV
复制代码

注:到这里,我们就可以把之前在application.yml 中的gateway 配置移动到 apollo中了;

解决apollo 更改配置项目不同步问题

/**
 * apollo 刷新 gateway配置不同步 问题解决
 */
@Component
public class GatewayPropertiesRefresher implements ApplicationContextAware, ApplicationEventPublisherAware {
    private static final Logger logger = LoggerFactory.getLogger(GatewayPropertiesRefresher.class);

    private ApplicationContext applicationContext;

    private ApplicationEventPublisher publisher;

    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }


    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        this.publisher = applicationEventPublisher;
    }

    @ApolloConfigChangeListener
    public void onChange(ConfigChangeEvent changeEvent) {
        this.applicationContext.publishEvent(new EnvironmentChangeEvent(changeEvent.changedKeys()));
        this.publisher.publishEvent(new RefreshRoutesEvent(this));
        logger.info("GatewayPropertiesRefresher.onChange apollo GatewayProperties refreshed");
    }
}
复制代码

4. 整合eureka

 <properties>
     <java.version>1.8</java.version>
     <lombok.version>1.18.10</lombok.version>
     <fastjson.version>1.2.78</fastjson.version>
     <spring-cloud-version>2.1.0.RELEASE</spring-cloud-version>
     <apollo-client.version>1.9.1</apollo-client.version>
 </properties>        

 <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
      <version>${spring-cloud-version}</version>
 </dependency>
复制代码

5. 整合sentinel

5.1 准备环境

参见:github-sentinel 快速启动项目;

5.2 项目配置

pom.xml

<!--alibaba 流量卫士-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
    <version>2.1.0.RELEASE</version>
</dependency>
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
    <version>2.1.0.RELEASE</version>
</dependency>
复制代码

application.yml

spring:  
  cloud:
    # sentinel 限流配置
    sentinel:
      transport:
        dashboard: yiyi.cn:18085
        port: 18085
      # 服务启动直接建立心跳连接
      eager: true
复制代码

运行校验

注:参见sentinel 官方文档, 整一个测试脚本 run一下即可

参见

Spring-Cloud-Gateway 源码解析 —— 网关管理 HTTP API

SpringCloud gateway (史上最全) - 疯狂创客圈 - 博客园

github-带注释版spring-cloud-gateway源码

Supongo que te gusta

Origin juejin.im/post/7047469654503063560
Recomendado
Clasificación