ZULL-zull过滤器和动态路由

1:zull过滤器

1:zull过滤器介绍

Zuul 中的过滤器跟我们之前使用的 javax.servlet.Filter 不一样,javax.servlet.Filter 只有一种类型,可以通过配置 urlPatterns 来拦截对应的请求。

而 Zuul 中的过滤器总共有 4 种类型,且每种类型都有对应的使用场景。

  1. pre:可以在请求被路由之前调用。适用于身份认证的场景,认证通过后再继续执行下面的流程
  2. route:在路由请求时被调用。适用于灰度发布场景,在将要路由的时候可以做一些自定义的逻辑
  3. post:在 route 和 error 过滤器之后被调用。这种过滤器将请求路由到达具体的服务之后执行。适用于需要添加响应头,记录响应日志等应用场景。
  4. error:处理请求时发生错误时被调用。在执行过程中发送错误时会进入 error 过滤器,可以用来统一记录错误信息。
    在这里插入图片描述
    如上所示,这是zullFilter的执行过程;请求发过来首先到 pre 过滤器,再到 routing 过滤器,最后到 post 过滤器,任何一个过滤器有异常都会进入 error 过滤器。
    在这里插入图片描述

2:zull过滤器源码

ZuulServlet 源码如下,从源码可以看出zull过滤器的生命周期;

@Override
public void service(javax.servlet.ServletRequest servletRequest, javax.servlet.ServletResponse servletResponse)
        throws ServletException, IOException {
    try {
        init((HttpServletRequest) servletRequest, (HttpServletResponse) servletResponse);
        RequestContext context = RequestContext.getCurrentContext();
        context.setZuulEngineRan();
        try {
            preRoute();
        } catch (ZuulException e) {
            error(e);
            postRoute();
            return;
        }
        try {
            route();
        } catch (ZuulException e) {
            error(e);
            postRoute();
            return;
        }
        try {
            postRoute();
        } catch (ZuulException e) {
            error(e);
            return;
        }
    } catch (Throwable e) {
        error(new ZuulException(e, 500, "UNHANDLED_EXCEPTION_" + e.getClass().getName()));
    } finally {
        RequestContext.getCurrentContext().unset();
    }
}

3:自定义过滤器步骤

写filter步骤。
1.继承zuulfilter
2.public boolean shouldFilter(0:true:执行此过滤器,false:不执行)
3.run:过滤器的业务逻辑
4.filterType pre,route,post,error
5.filter order:数字越小,越先执行

2:过滤器使用

1:使用过滤器来实现ip黑名单

public class IpFilter extends ZuulFilter {

    // IP黑名单列表
    private List<String> blackIpList = Arrays.asList("127.0.0.1");

    public IpFilter() {
        super();
    }

    @Override
    public boolean shouldFilter() {
        return true
    }

    @Override
    public String filterType() {
        return "pre";
    }

    @Override
    public int filterOrder() {
        return 1;
    }

    @Override
    public Object run() {
        RequestContext ctx = RequestContext.getCurrentContext();
        String ip = IpUtils.getIpAddr(ctx.getRequest());
        // 在黑名单中禁用
        if (StringUtils.isNotBlank(ip) && blackIpList.contains(ip)) {

			//拦截不让往下走,还走剩下的过滤器,但是不向后面的服务转发。
            ctx.setSendZuulResponse(false);
            ResponseData data = ResponseData.fail("非法请求 ", ResponseCode.NO_AUTH_CODE.getCode());
            ctx.setResponseBody(JsonUtils.toJson(data));
            ctx.getResponse().setContentType("application/json; charset=utf-8");
            return null;
        }
        return null;
    }
}

2:默认zull请求中的token不向后变服务传传

通过查看源码得知,默认这些东西zull都不会向后传,因为zull就是为了做鉴权的
在这里插入图片描述
如果想要向后传,只需要将sensitive-headers置为空

zuul:
  sensitive-headers:

3:动态路由装换

加入一个老项目改造,需要引入新的框架zull,但是我们曾经对外暴露过一个/test21接口,现在新的服务中我们定义为了/test2接口,那么可以使用zull来实现动态路由装换;也就是用户请求/test21接口,我们可以映射到/test2接口

package com.mashibing.cloudzuul.filter;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;

/**
 * Description:
 * Date:       2022/5/18 - 下午 6:50
 * author:     wangkanglu
 * version:    V1.0
 */
@Component
public class UrlMappingFilter extends ZuulFilter {
    @Override
    public String filterType() {
        return FilterConstants.ROUTE_TYPE;
    }

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

    /**
     * @return false 关闭该过滤器
     */
    @Override
    public boolean shouldFilter() {
        return true;
    }

    @Override
    public Object run() {
        RequestContext currentContext = RequestContext.getCurrentContext();
        HttpServletRequest request = currentContext.getRequest();
        String requestURI = request.getRequestURI();
        //用于截取服务名与访问地址
        requestURI = requestURI.substring(1);
        String[] urlPart = requestURI.split("/", 2);
        //这个是服务名,可以去其他地方(配置、db)获取
        String serviceId = urlPart[0];
        String sourceUrl = urlPart[1];

        Map<String, String> urlMapping = getUrlMapping();

        if (urlMapping != null && urlMapping.containsKey(sourceUrl)) {
            String targetUrl = urlMapping.get(sourceUrl);
            //上面的serviceId(微服务名)是从URL中截取的,如果需要访问其他serviceId就需要重新定义serviceId,替换成你需要访问的服务名,否则会爆404
            currentContext.set(FilterConstants.SERVICE_ID_KEY, serviceId);
            currentContext.set(FilterConstants.REQUEST_URI_KEY, targetUrl);
        }
        return null;
    }

    private Map<String, String> getUrlMapping() {
        // TODO: 2022/3/28  这里返回一个map映射关系,映射关系可以存库等,下面是我造的数据测试用
        HashMap hashMap = new HashMap();
        hashMap.put("test/sms-test31", "/test/sms-test3");
        hashMap.put("test/sms-test41", "/test/sms-test4");
        hashMap.put("test/sms-test51", "/test/sms-test5");
        return hashMap;
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

苍煜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值