美文网首页
Spring cloud微服务实战(四)——动态改变Zuul的路

Spring cloud微服务实战(四)——动态改变Zuul的路

作者: 新学年 | 来源:发表于2020-06-01 18:01 被阅读0次

    发布了两年多的文章今天发现被CSDN关了, 理由如下:


    image.png

    现在迁移到简书看看是否有问题。

    背景

    最近做个项目需要暴露API给其他系统进行对接,为了方便第三方系统对接和不暴露后台服务,就不把具体的服务暴露出来。
    所有的请求只有一个入口,如:http://xxxxxxx/api,就设计了如下的请求参数:
    
    {
    "BIZ_TYPE":"userInfo",
    "REQ_TIME":"2018-06-06 10:08:00",
    "REQ_ID":"20171121162959347258",
    "AUTH_ID":"GZ_SIGNKEY",
    "PARAM":{
    "AREA":"12121",
    "SOCIAL_CREDIT_CODE":"91110302100026582U",
    "INDUSTRY_CODE":"JHDF43"
    }
    
    

    其中主要关注BIZ_TYPE,这个就用来动态选择服务的,Zuul拦截之后拿BIZ_TYPE去数据库里查询对应的service_id和URL,最后进行动态更换。数据库表如下

    DROP TABLE IF EXISTS `trace_route`;
    CREATE TABLE `trace_route` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `service_id` varchar(255) NOT NULL COMMENT '微服务id',
      `biz_type` varchar(255) DEFAULT NULL COMMENT '数据类型',
      `url` varchar(255) DEFAULT NULL COMMENT '请求地址',
      `category` varchar(255) DEFAULT NULL COMMENT '所属类别',
      `remark` varchar(255) DEFAULT NULL COMMENT '备注',
      `create_date` datetime DEFAULT NULL,
      `update_date` datetime DEFAULT NULL,
      PRIMARY KEY (`id`),
      UNIQUE KEY `BIZ_TYPE_UNIQUE` (`biz_type`) USING BTREE
    ) ENGINE=InnoDB AUTO_INCREMENT=31 DEFAULT CHARSET=utf8;
    

    示例如下:


    在这里插入图片描述

    实现

    实现ZuulFilter

    这个不用多说,主要为了在Zuul进行路由之前动态修改service_id和和Url,代码示例如下:

    Component
    @Slf4j
    public class AccessFilter extends ZuulFilter {
        private ObjectMapper objectMapper = new ObjectMapper();
        @Autowired
        private TraceRouteService traceRouteService;
    
        @Autowired
        private RouteLocator routeLocator;
    
        @Override
        public String filterType() {
            return FilterConstants.PRE_TYPE;
        }
    
        @Override
        public int filterOrder() {
            return FilterConstants.PRE_DECORATION_FILTER_ORDER + 1;//PreDecorationFilter会对服务做封装,故在它之后修改
        }
    
        @Override
        public boolean shouldFilter() {
            return true;
        }
    
        @Override
        public Object run() throws ZuulException {
            RequestContext ctx = RequestContext.getCurrentContext();
            HttpServletRequest request = ctx.getRequest();
            log.info("请求url:{}",request.getRequestURI());
            Object originalRequestPath = ctx.get(FilterConstants.REQUEST_URI_KEY);
          
            try {
                BufferedReader reader = new BufferedReader(new InputStreamReader(request.getInputStream(),"UTF-8"));
                String str;
                String wholeBody = "";
                while((str = reader.readLine()) != null){
                    wholeBody += str;
                }
                Gson gson = new Gson();
                RequestBodyHeader requestBodyHeader = gson.fromJson(jsonBody,RequestBodyHeader.class);
                
                //重点:动态设置转发的服务
                String bizType = requestBodyHeader.getBIZ_TYPE();
                TraceRoute route = traceRouteService.findByBizType(bizType);
                ctx.put(FilterConstants.SERVICE_ID_KEY, route.getServiceId());
                if (route.getUrl().startsWith("/")){
                    ctx.put(FilterConstants.REQUEST_URI_KEY, route.getServiceId() + route.getUrl());
                }else {
                    ctx.put(FilterConstants.REQUEST_URI_KEY, route.getServiceId() + "/" + route.getUrl());
                }
                ctx.put(FilterConstants.PROXY_KEY,route.getServiceId());
            } catch (IOException e) {
                e.printStackTrace();
                doNotTransmit(ctx,Constant.UNKNOW_ERR_CODE,Constant.UNKNOW_ERR_MSG);
            }
            return null;
        }
    }
    

    重点

    上面的代码的重点部分如下:

                String bizType = requestBodyHeader.getBIZ_TYPE();
                TraceRoute route = traceRouteService.findByBizType(bizType);
                ctx.put(FilterConstants.SERVICE_ID_KEY, route.getServiceId());
                if (route.getUrl().startsWith("/")){
                    ctx.put(FilterConstants.REQUEST_URI_KEY, route.getServiceId() + route.getUrl());
                }else {
                    ctx.put(FilterConstants.REQUEST_URI_KEY, route.getServiceId() + "/" + route.getUrl());
                }
                ctx.put(FilterConstants.PROXY_KEY,route.getServiceId());
    

    很简单,通过bizType 去数据库查找对应的service_id和url,然后进行替换。
    1.替换service_id
    ctx.put(FilterConstants.PROXY_KEY,route.getServiceId());
    2.替换请求的URL
    ctx.put(FilterConstants.REQUEST_URI_KEY, route.getServiceId() + route.getUrl());

    示例

    发起请求 http://xxxxxx/api(用PostMan的选raw)
    {
    "BIZ_TYPE":"userInfoList",
    "REQ_TIME":"2018-06-06 10:08:00",
    "REQ_ID":"20171121162959347258",
    "AUTH_ID":"GZ_SIGNKEY",
    "PARAM":{
    "AREA":"12121",
    "SOCIAL_CREDIT_CODE":"91110302100026582U",
    "INDUSTRY_CODE":"JHDF43"
    }
    通过解析BIZ_TYPE,获得service_id为user,url为user/list,替换service_id和URL后就会路由到具体的服务里面。

    彩蛋

    需要的yml文件中配置如下
    zuul:
    routes:
    dataservice:
    path: /api/**
    serviceId: api

    相关文章

      网友评论

          本文标题:Spring cloud微服务实战(四)——动态改变Zuul的路

          本文链接:https://www.haomeiwen.com/subject/nybszhtx.html