SpringCloud Gateway

网关:官方中文文档 

系统的统一入口,为客户端提供统一的服务

创建gateway maven项目引入依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

添加配置文件:

server:
  port: 8070
spring:
  application:
    name: wdz-gateway

  cloud:
    gateway:
      routes: # 路由数组
        - id: wdz_product # 当前路由的标识,唯一,默认是UUID,通常配置为项目名称
          uri: http://localhost:8072 # 请求转发目标地址
          order: 1 #路由优先级,数字越小优先级越高
          predicates: # 断言 条件判断,返回值是Boolean 转发请求要求满足的条件
            - Path=/product/** 
           # 当请求路径满足Path指定的规则时,路由信息才会正常转发,
           # 如果直接配置 / 则不需要配置filters
           # 以上配置转发信息:localhost:8087/product/get/1 
           # ---->  http://localhost:8072/product/get/1
          filters: # 过滤器,在请求传递过程中,队请求做一些业务处理
            - StripPrefix=1 # 在请求转发之前去掉一层路径
          # StripPrefix配置转发信息:localhost:8087/product/get/1 
          # ----> http://localhost:8072/get/1

访问路径:

http://localhost:8070/product/query/1  就直接转发到  http://localhost:8072/query/1

集成nacos

引入依赖:

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-alibaba-nacos-discovery</artifactId>
</dependency>

启动类添加注解:@EnableDiscoveryClient

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

修改配置文件:

server:
  port: 8070
spring:
  application:
    name: wdz-gateway
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
    gateway:
      discovery:
        locator:
          enabled: true   # 开启从nacos中获取信息
      routes: # 路由数组
        - id: wdz_product # 当前路由的标识,唯一,默认是UUID,通常配置为项目名称
          # uri: http://localhost:8072 # 请求转发目标地址
          # 集成nacos之后
          uri: lb://wdz-product #lb:负载均衡, 请求的目标服务器名称
          order: 1 #路由优先级,数字越小优先级越高
          predicates: # 断言 条件判断,返回值是Boolean 转发请求要求满足的条件
            - Path=/product/** 
            # 当请求路径满足Path指定的规则时,路由信息才会正常转发,
            # 如果直接配置 / 则不需要配置filters
            # 以上配置转发信息:localhost:8087/product/get/1 
            #----> http://localhost:8072/product/get/1
          filters: # 过滤器,在请求传递过程中,队请求做一些业务处理
            - StripPrefix=1 # 在请求转发之前去掉一层路径
          # StripPrefix配置转发信息:localhost:8087/product/get/1 
          # ----> http://localhost:8072/get/1



重启服务:访问地址变更:

http://localhost:8070/wdz-product/query/1

http://localhost:8070/:是网关地址

wdz-product: 要访问的目标服务名称spring.application.name

query/1:目标服务中的接口

routes:路由数组数据配置默认gateway的,可直接通过上边路径访问,但是不够灵活,如果多条path配置就只能手动配置了,日常开发中建议使用配置,这样更方便的去管理服务

概念:

执行流程:

 断言:predicates

用于进行条件判断,只有断言都返回true,才会真正的转发路由

 

 

断言:

1:继承AbstractRoutePredicateFactory
2:配置+RoutePredicateFactory  命名规则

配置是指在yml文件断言下配置的参数
配置文件:

自定义代码:

@Component
public class AgeRoutePredicateFactory extends  AbstractRoutePredicateFactory<AgeRoutePredicateFactory.Config> {

    // 构造
    public AgeRoutePredicateFactory() {
        super(AgeRoutePredicateFactory.Config.class);
    }
    // 读取配置文件中的参数值,赋值到配置类的属性中
    @Override
    public List<String> shortcutFieldOrder() {
        List<String> strings = Arrays.asList("age");
        return strings;
    }

    // 断言逻辑
    @Override
    public Predicate<ServerWebExchange> apply(AgeRoutePredicateFactory.Config config) {

        return new Predicate<ServerWebExchange>() {
            @Override
            public boolean test(ServerWebExchange serverWebExchange) {
                // 接收前端传入的参数:age
                String age = serverWebExchange.getRequest().getQueryParams().getFirst("age");
                if (!StringUtils.isEmpty(age)){
                    int i = Integer.parseInt(age);
                    if (i == config.getAge()){
                        return true;
                    }else {
                        return false;
                    }
                }
                return false;
            }
        };
    }
    // 用于接收 配置文件中对应的参数
    @Data
    @NoArgsConstructor
    public static class Config {
        private int age;

    }
}

http://localhost:8070/product/query/1?age=18

请求路径要满足Path 才能进入断言

过滤器:

作用:在请求传递的过程中,对请求和响应做一些业务处理

生命周期:

        路由之前(pre):这种过滤器在请求路由之前调用,可利用这个过滤器实现身份验证、通过某些条件选择服务、记录调试信息等

        路由之后(post):这种过滤器是在路由到微服务之后执行,这种过滤器可用来为响应添加标准的http  header,收集统计信息和指标,将响应从微服务发送给客户端等

分类:

从作用范围可分为:

GatewayFilter:应用到单个路由或者一个分组的路由上

GlobalFilter:应用到所有的路由上

 

 自定义过局部滤器:

规则与断言格式基本一致

继承 AbstractGatewayFilterFactory

命名规则:配置+GatewayFilterFactory

package com.wdz.cloud.gateway.filter;

import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.Arrays;
import java.util.List;

/**
 * 自定义局部过滤器
 */
@Component
public class LogGatewayFilterFactory extends AbstractGatewayFilterFactory<LogGatewayFilterFactory.Config> {

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

    @Override
    public List<String> shortcutFieldOrder() {
        return Arrays.asList("consoleLog","cacheLog");
    }

    @Override
    public GatewayFilter apply(Config config) {
         GatewayFilter filter = new GatewayFilter() {
            @Override
            public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
                System.out.println("-------------过滤器参数值:" + config.toString());
                if (config.isCacheLog()){
                    System.out.println("缓存日志开启");
                }
                if (config.isConsoleLog()){
                    System.out.println("控制台日志开启");
                }
                return chain.filter(exchange);
            }
        };
        return filter;
    }


    @Data
    @NoArgsConstructor
    public static class Config {
        private boolean consoleLog;
        private boolean cacheLog;
    }
}

自定义全局过滤器:

package com.wdz.cloud.gateway.filter;

import org.apache.commons.lang3.StringUtils;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

/**
 * 自定义全局过滤器
 * 要求:
 * 必须实现GlobalFilter, Ordered,并实现接口
 */
@Component
public class AuthGlobalFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String token = exchange.getRequest().getQueryParams().getFirst("token");
        if (StringUtils.isEmpty(token)){
            System.out.println("---------认证失败------");
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }
        // 放行
        return chain.filter(exchange);
    }

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

这样就完成简单的全局过滤器,如果未认证则返回httpstatus=401

跨域问题处理:

方式一:配置文件方式

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

方式二 :java代码方式

package com.wdz.gateway.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.cors.reactive.CorsUtils;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;

/**
 * 跨域配置
 */
@Configuration
public class CorsConfig {

    /**
     * 这里为支持的请求头,如果有自定义的header字段请自己添加
     */
    private static final String ALLOWED_HEADERS = "X-Requested-With, Content-Type,device ,Authorization, credential, X-XSRF-TOKEN, token, Admin-Token, App-Token";

    private static final String ALLOWED_METHODS = "GET,POST,PUT,DELETE,OPTIONS,HEAD";

    private static final String ALLOWED_ORIGIN = "*";

    private static final String ALLOWED_EXPOSE = "*";

    private static final String MAX_AGE = "3600L";

    @Bean
    public WebFilter corsFilter() {
        return (ServerWebExchange ctx, WebFilterChain chain) -> {
            ServerHttpRequest request = ctx.getRequest();
            if (CorsUtils.isCorsRequest(request)) {
                ServerHttpResponse response = ctx.getResponse();
                HttpHeaders headers = response.getHeaders();
                headers.add("Access-Control-Allow-Headers", ALLOWED_HEADERS);
                headers.add("Access-Control-Allow-Methods", ALLOWED_METHODS);
                headers.add("Access-Control-Allow-Origin", ALLOWED_ORIGIN);
                headers.add("Access-Control-Expose-Headers", ALLOWED_EXPOSE);
                headers.add("Access-Control-Max-Age", MAX_AGE);
                headers.add("Access-Control-Allow-Credentials", "true");
                if (request.getMethod() == HttpMethod.OPTIONS) {
                    response.setStatusCode(HttpStatus.OK);
                    return Mono.empty();
                }
            }
            return chain.filter(ctx);
        };
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值