SpringCloud集成GatWay服务网关以及过滤器

摘要:

GateWay与Zuul一样,都是服务网关,所做的事也是一样的,不同在于GateWay是SpringCloud自己的组件,就是为了替代Zuul,SpringCloud高版本已经没有对Zuul2.0进行集成了

一:引入依赖

<dependencies>
    <!--引入Eureka的客户端依赖,不需要引入spring-boot-start-web包,因为gateway有自己的启动包-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
    <!--引入gateway依赖-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-gateway</artifactId>
    </dependency>
</dependencies>

二:编写配置文件

server:
    port: 10006 #gateway服务端口号

eureka:
    client: #Eureka客户端配置,指向注册中心地址
        serviceUrl:
            defaultZone: http://localhost:10001/eureka/
    instance:
        prefer-ip-address:true #开启使用IP地址进行注册
        instance-id: GatWayServer:10006 #修改实例Id
spring:
    application: #指定此服务的应用名称
        name: GatWayServer
    cloud:
        gateway:
            discovery:
                locator:
                    enabled: false #指定关闭通过服务名访问,默认就是关闭
                    lower-case-service-id: true #服务名称小写
            routes:
                -id: application-user#指定当前路由配置的Id,需要唯一
                uri: lb://UserServer#去注册中心找这个服务名
                predicates: #断言,匹配访问的路径
                    -Path=/user/** #服务访问路径
                filters:
                    -StripPrefix=1 #请求转发的时候会去掉/user访问路径,数字代表要去掉的前缀个数

集成完毕!GateWay会根据发送的请求是否以predicates断言的指定路径开头,如果是则指向到uri的微服务

===============================================GateWay过滤器===============================================

摘要:

GateWay的过滤器与Zuul的Filter有相似之处,不同在于GateWay从生命周期上只分为pre和post两种

GateWay的过滤器和自己的断言也有相似之处,都是为了判定请求是否以指定规则一致,是则转发,否则拦截,其实就是一个是配置文件写的,一个是代码实现的,代码实现的可以写更多的逻辑处理

一:自定义单个路由的GateWayFilter【由自定义filter和配置类组成】

创建自定义filter:

package cn.itsource.filter;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.core.Ordered;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

/**
	  * @Description: 自定义一个计算请求调用链耗时的filter
	 */
public class RequestTimeFilter implements GatewayFilter, Ordered {

    // 创建日志器,可以使用slf4j提供的日志器进行日志打印
    private static final Logger log = LoggerFactory.getLogger(RequestTimeFilter.class);

    /*
	     * @Description: 在这个方法中可以写拦截后的逻辑处理,这里是打印了调用链的耗时
	     * @Author: Director
	     * @Date: 2022/7/29 18:05
	     * @param exchange: 服务网络交换器,存放着重要的请求-响应属性、请求实例和响应实例等等,类似于请求上下文对象
	     * @param chain: Gateway的filter调用链对象
	     **/
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 打印当前客户端请求的地址
        String path = exchange.getRequest().getURI().getPath();
        log.info("RequestTimeFilter执行,请求路径为:{}", path);

        // 存入进入请求时的开始时间
        exchange.getAttributes().put("startTime", System.currentTimeMillis());

        // 执行完成之后
        return chain.filter(exchange).then(
            Mono.fromRunnable(() -> {
                // 开始时间
                Long startTime = exchange.getAttribute("startTime");
                // 结束时间
                Long endTime = (System.currentTimeMillis() - startTime);
                // 打印当前请求耗时
                log.info(exchange.getRequest().getURI().getRawPath() + ": " + endTime + "ms");
            })
        );
    }

    /*
	     * @Description: 执行时机,默认为0
	     **/
    @Override
    public int getOrder() {
        return 0;
    }
}

配置filter以及对哪个路由生效:

package cn.itsource.config;

import cn.itsource.filter.RequestTimeFilter;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
	 * @Description: 自定义过滤器的配置类
	 */
@Configuration // 标识当前类是一个配置类
public class FilterConfig {

    // 配置Filter作用于那个访问规则上:/user/**
    @Bean
    public RouteLocator customerRouteLocator(RouteLocatorBuilder builder) {
        return builder.routes().route(r -> r.path("/user/**")
                                      //去掉1个前缀
                                      .filters(f -> f.stripPrefix(1)
                                               .filter(new RequestTimeFilter())
                                               .addResponseHeader("X-Response-test", "test"))
                                      .uri("lb://user-server")
                                      .order(0)
                                      .id("test-RequestTimeFilter")
                                     ).build();
    }
}

二:自定义针对所有路由的GlobalFiler

与GateWayFilter不同,它不需要配置类进行配置,只需要交给Spring进行管理即可

package cn.itsource.filter;

import com.alibaba.fastjson.JSON;
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.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
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.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.List;

@Component // 将当前类交给spring管理
@Slf4j // lombok提供的注解使用logger打印器
public class LoginCheckFilter implements GlobalFilter, Ordered {

    /*
	 * @Description: 自定义GlobalFilter的核心方法【判断请求头中是否含有token】
	 * @param exchange: 服务网络交换器,存放着重要的请求-响应属性、请求实例和响应实例等等,类似于请求上下文对象
	 * @param chain: filter调用链对象
	 **/
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

        // 1.从请求头中获取token,此处获取到的是一个集合
        List<String> token = exchange.getRequest().getHeaders().get("token");

        log.info("检查 TOKEN = {}" ,token);

        // 2.判断token请求头是否为空,如果为空抛出异常,说明未登录
        if(token == null || token.isEmpty()){
            // 1.响应对象
            ServerHttpResponse response = exchange.getResponse();
            // 2.构建错误结果
            HashMap<String,Object> data = new HashMap<>();
            // 3.设置响应信息
            data.put("code", 401);
            data.put("success", false);
            data.put("message","登录校验失败,请重新登录!");

            DataBuffer buffer = null;
            try {
                //  4.转换参数,包装buffer对象
                // 4.1.将数据转换为JSON,再转换为byte数组
                byte[] bytes = JSON.toJSONString(data).getBytes("utf-8");
                // 4.2.将byte数组包装到DataBuffer对象中,用于响应给浏览器,构建响应内容
                buffer = response.bufferFactory().wrap(bytes);

                // 5.设置完成响应,不会继续执行后面的filter
                // 5.1.设置响应状态为401
                response.setStatusCode(HttpStatus.UNAUTHORIZED);
                // 5.2.设置响应格式
                response.getHeaders().add("Content-Type","application/json;charset=UTF-8");
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }

            // 6.把结果写给客户端
            return response.writeWith(Mono.just(buffer));
        }

        log.info("Token不为空 ,放行");
        // 7.token不为空,继续执行后续filter
        return chain.filter(exchange);
    }

    /*
	 * @Description: filter的执行时机
	 **/
    @Override
    public int getOrder() {
        return 0;
    }
}

 三:GateWay跨域配置

	spring:
	        cloud:
	                globalcors:#跨域配置
	                        cors-configurations:
	                                '[/**]':
	                                allowedOrigins:"https://docs.spring.io"#允许的站点可以为*
	                                allowedMethods:#允许的请求方式
	                                        -GET
	                                        -POST
	                                        -DELETE
	                                        -PUT
	                                        -HEAD
	                                        -CONNECT
	                                        -TRACE
	                                        -OPTIONS
	                                allowHeaders:#允许的请求头
	                                        -Content-Type

 

posted @ 2022-08-22 13:30  yyybl  阅读(73)  评论(0)    收藏  举报