springCloud Alibaba教程-网关gateway入门实践(下)

1. gateway过滤器

Gateway中Filter的生命周期只有两个:pre 和 post:
PRE: 这种过滤器在请求被路由之前调用,可实现身份验证。
POST:这种过滤器在路由到微服务以后执行,可用来为响应添加标准的HTTP Header、收集统计信息和指标、将响应从微服务发送给客户端等。

Gateway 的Filter从作用范围可分为两种: GatewayFilter与GlobalFilter。 GatewayFilter:应用到单个路由或者一个分组的路由上,GlobalFilter:应用到所有的路由上。

内置过滤器:

过滤器工厂作用使用
AddRequestHeader为原始请求添加Header- AddRequestHeader=X-Request-red, blue
AddRequestParameter为原始请求添加请求参数- AddRequestParameter=color, blue
AddResponseHeader为原始响应添加Header- AddResponseHeader=X-Response-Red, Blue
DedupeResponseHeader剔除响应头中重复的值- DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin
CircuitBreakerspring cloud gateway 熔断器,支持resilience4j在这里插入图片描述
FallbackHeaders为fallbackUri的请求头中添加具 体的异常信息在这里插入图片描述
MapRequestHeader从已有的请求头中获取值,并赋值给一个新的请求头- MapRequestHeader=Blue, X-Request-Red
PrefixPath为原始请求路径添加前缀- PrefixPath=/mypath
PreserveHostHeader为请求添加一个 preserveHostHeader=true的属 性,路由过滤器会检查该属性以 决定是否要发送原始的Host- PreserveHostHeader
RequestRateLimiter用于对请求限流,限流算法为令牌桶
RedirectTo将原始请求重定向到指定的URL
RemoveHopByHopHeadersFilter删除header- RemoveResponseHeader=X-Response-Foo
RemoveRequestParameter删除参数- RemoveRequestParameter=red
RequestHeaderSize限制请求头大小,超过限制大小将会返回431- RequestHeaderSize=1000B
RewritePath重写原始的请求路径- RewritePath=/red/?(?.*), /${segment}
RewriteResponseHeader重写原始响应中的某个Header
SaveSession在转发请求之前,强制执行- SaveSession
SecureHeaders为原始响应添加一系列起安全作用的响应头spring.cloud.gateway.filter.secure-headers.disable=x-frame-options,strict-transport-security
SetPath修改原始的请求路径
SetResponseHeader修改原始响应中某个Header的值- SetRequestHeader=X-Request-Red, Blue
SetRequestHeader修改请求头的值- SetRequestHeader=X-Request-Red, Blue
SetStatus修改原始响应的状态码- SetStatus=401
StripPrefix用于截断原始请求的路径,使用数字表示要截断的路径的数量- StripPrefix=2
Retry针对不同的响应进行重试
RequestSize设置允许接收最大请求包的大小。如果请求包大小超过设置的值,则返回413,请求包大小,单位为字 节,默认值为5M
SetRequestHostHeader设置请求host
ModifyRequestBody在转发请求之前修改原始请求体
内容
ModifyResponseBody修改响应内容

2 自定义过滤器

自定义一个过滤器打印请求日志
在配置文件中配置:

# true/false控制日志是否开启
- MyLog=true

自定义一个过滤器工厂:

/**
 * 自定义过滤器
 */
@Component
public class MyLogGatewayFilterFactory extends AbstractGatewayFilterFactory<MyLogGatewayFilterFactory.MyLogConfig> {


    public MyLogGatewayFilterFactory() {
        super(MyLogConfig.class);
    }

    /**
     * 读取配置文件中的参数 赋值到 配置类中
     * @return
     */
    @Override
    public List<String> shortcutFieldOrder() {
        return Arrays.asList("showLog");
    }

    @Override
    public GatewayFilter apply(MyLogConfig config) {
        return new GatewayFilter() {
            @Override
            public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
                if (config.showLog) {
                    System.out.println("请求路径:" + exchange.getRequest().getPath());
                }
                return chain.filter(exchange);
            }
        };
    }

    /**
     * 配置类接收配置的参数
     */
    public static class MyLogConfig {
        private boolean showLog;

        public boolean isShowLog() {
            return showLog;
        }

        public void setShowLog(boolean showLog) {
            this.showLog = showLog;
        }
    }
}

然后启动测试:
在这里插入图片描述

3 自定义全局过滤器

全局过滤器作用于所有路由, 无需配置。通过全局过滤器可以实现对权限的统一校验,安全性验证等功能。开发一个全局过滤器实现接口的统一鉴权,大概逻辑为:当客户端第一次请求服务时,服务端对用户进行信息认证(登录) ,如果认证通过,将用户信息进行加密形成token,返回给客户端,作为登录凭证; 以后每次请求,客户端都携带认证的token 服务端对token进行解密,判断是否有效。自定义全局过滤器需要实现GlobalFilter和Ordered接口。

@Component
public class AuthGlobalFilter implements GlobalFilter, Ordered {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String token = exchange.getRequest().getHeaders().getFirst("token");
        if (StringUtils.hasText(token)) {
            // TODO 处理鉴权逻辑
            System.out.println("auth: 鉴权成功");
            return chain.filter(exchange);
        } else {
            System.out.println("auth: token丢失!!");
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }
    }

    /**
     * 数值越小越先执行
     * @return
     */
    @Override
    public int getOrder() {
        return 0;
    }
}

4 网关限流

网关是所有请求的公共入口,所以可以在网关进行限流,而且限流的方式也很多。Sentinel支持对SpringCloud Gateway、Zuul等主流网关进 行限流。从1.6.0版本开始,Sentinel提供了SpringCloud Gateway的适配模块,可以提供两种资源维度的限流: route维度,即在Spring配置文件中配置的路由条目,资源名为对应的routeId;自定义API维度,用户可以利用Sentinel提供的API来自定义一些API分组。

使用sentinel实现网关限流需要先引入依赖:

<dependency>
    <groupId>com.alibaba.csp</groupId>
     <artifactId>sentinel-spring-cloud-gateway-adapter</artifactId>
</dependency>

限流配置:

package com.tdt.platformcloud.gateway.config;

import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayFlowRule;
import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayRuleManager;
import com.alibaba.csp.sentinel.adapter.gateway.sc.SentinelGatewayFilter;
import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.BlockRequestHandler;
import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.GatewayCallbackManager;
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.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.web.reactive.function.BodyInserter;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.ServerResponse;
import org.springframework.web.reactive.result.view.ViewResolver;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import javax.annotation.PostConstruct;
import java.util.*;

/**
 * 请求限流配置
 */
@Configuration
public class RequestLimitConfig {

    private final List<ViewResolver> viewResolvers;
    private final ServerCodecConfigurer serverCodecConfigurer;

    public RequestLimitConfig(ObjectProvider<List<ViewResolver>> viewResolversProvider, ServerCodecConfigurer serverCodecConfigurer) {
        this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);
        this.serverCodecConfigurer = serverCodecConfigurer;
    }

    /**
     * 初始化限流过滤器
     * @return
     */
    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public GlobalFilter sentinelGatewayFilter() {
        return new SentinelGatewayFilter();
    }

    /**
     * 配置初始化的限流参数
     */
    @PostConstruct
    public void initGatewayRules() {
        Set<GatewayFlowRule> rules = new HashSet<>();
        rules.add(new GatewayFlowRule("product_route") // 资源名称,对应路由ID
                .setCount(1)  // 阈值
                .setIntervalSec(1)); // 统计时间窗口,单位是秒,默认1s
        GatewayRuleManager.loadRules(rules);
    }

    /**
     * 限流异常处理器
     * @return
     */
    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler() {
        return new SentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);
    }

    /**
     * 自定义限流异常页面
     */
    @PostConstruct
    public void initBlockHandlers() {
        BlockRequestHandler blockRequestHandler = new BlockRequestHandler() {
            @Override
            public Mono<ServerResponse> handleRequest(ServerWebExchange serverWebExchange, Throwable throwable) {
                Map<String, Object> result = new HashMap<>();
                result.put("code", 0);
                result.put("message", "接口被限流了,稍后再试");
                return ServerResponse.status(HttpStatus.OK)
                        .contentType(MediaType.APPLICATION_JSON)
                        .body(BodyInserters.fromValue(result));
            }
        };
        GatewayCallbackManager.setBlockHandler(blockRequestHandler);
    }
}

然后测试一下:
在这里插入图片描述
还可以自定义api分组进行更细粒度的限流。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值