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

发布了两年多的文章今天发现被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的路由规则)