概述

组件是网关的核心,大部分功能特性都可以基于组件的形式提供,组件化可以有效提高网关的扩展性。

先来看一个简单的微信认证组件的例子:

如下实现的功能是对API请求传入的Token进行校验,其结果分别是认证通过、Token过期和无效Token,认证通过后再将微信OpenID携带给上游服务系统。

/**

*微信token认证,token格式:

* {appID:'',openID:'',timestamp:132525144172,sessionKey: ''}

*/

public class WeixinAuthTokenCmpt extends AbstractCmpt {

private static Logger logger = LoggerFactory.getLogger(WeixinAuthTokenCmpt.class);

private final CmptResult SUCCESS_RESULT;

public WeixinAuthTokenCmpt() {

SUCCESS_RESULT = buildSuccessResult();

}

@Override

public CmptResult execute(CmptRequest request, Map<String, FieldDTO> config) {

if (logger.isDebugEnabled()) {

logger.debug("WeixinTokenCmpt ......");

}

CmptResult cmptResult = null;

//Token认证超时间(传入单位:分)

long authTokenExpireTime = getAuthTokenExpireTime(config);

WeixinTokenDTO authTokenDTO = this.getAuthTokenDTO(request);

logger.debug("Token=" + authTokenDTO);

AuthTokenState authTokenState = validateToken(authTokenDTO, authTokenExpireTime);

switch (authTokenState) {

case ACCESS: {

cmptResult = SUCCESS_RESULT;

Map<String, String> header = new HashMap<>();

header.put(HeaderKeyConstants.HEADER_APP_ID_KEY, authTokenDTO.getAppID());

header.put(CmptHeaderKeyConstants.HEADER_WEIXIN_OPENID_KEY, authTokenDTO.getOpenID());

header.put(CmptHeaderKeyConstants.HEADER_WEIXIN_SESSION_KEY, authTokenDTO.getSessionKey());

cmptResult.setHeader(header);

break;

}

case EXPIRED: {

cmptResult = buildCmptResult(RespErrCode.AUTH_TOKEN_EXPIRED, "token过期,请重新获取Token!");

break;

}

case INVALID: {

cmptResult = buildCmptResult(RespErrCode.AUTH_INVALID_TOKEN, "Token无效!");

break;

}

}

return cmptResult;

}

...

}

上面例子看不懂没关系,接下来会详细阐述组件的设计思路。

二、基础结构说明

2.1组件接口定义

public interface ICmpt {

/**

*组件执行入口

*

* @param request

* @param config,组件实例的参数配置

* @return

*/

CmptResult execute(CmptRequest request, Map<String, FieldDTO> config);

/**

*销毁组件持有的特殊资源,比如线程。

*/

void destroy();

}

execute是组件执行的入口方法,request前面提到过是http请求的封装,config是组件的特殊配置,比如上面例子提到的微信认证组件就有一个自定义配置-Token的有效期,不同的API使用该组件可以设置不同的有效期。

2.1.1 FieldDTO定义

public class FieldDTO {

private String title;

private String name;

private FieldType fieldType = FieldType.STRING;

private String defaultValue;

private boolean required;

private String regExp;

private String description;

}

2.1.2组件返回结果定义

CmptResult为组件执行后的返回结果,其定义如下:

public class CmptResult {

RespErrMsg respErrMsg;//组件返回错误信息

private boolean passed;//组件过滤是否通过

private byte[] data;//组件返回数据

private Map<String, String> header = new HashMap<String, String>();//透传后端服务响应头信息

private MediaType mediaType;//返回响应数据类型

private Integer statusCode = 200;//默认返回状态码为200

}

2.3组件类型定义

执行器需要根据组件类型和组件执行结果判断是要直接返回客户端还是继续往下面执行,比如认证类型的组件,如果认证失败是不能继续往下执行的,但缓存类型的组件没有命中才继续往下执行。当然这样设计存在一些缺陷,比如新增组件类型需要执行器配合调整处理逻辑。

初步定义如下组件类型:

认证、鉴权、流量管控、缓存、路由、日志、其它等。

其中路由类型的组件涵盖了协议转换的功能,其负责调用上游系统提供的服务,可以根据上游系统提供API的协议定制不同的路由组件,比如:Restful、WebService、Dubbo、EJB等等。

补充说明:

1)用户自定义开发的组件如果不能划分到前面6种类型,可以将类型指定为其它,对于其它类型的组件其执行位置可以在Pre,也可以是After。

2)执行位置在Pre,且组件执行结果为通过的时候,引擎会将组件返回结果的头信息加入上下文;如果执行不通过引擎将组件结果直接返回客户端。

3)执行位置在After,组件执行结果为通过的情况引擎不做任何处理,只有执行结果为不通过的情况,引擎才将组件结果直接返回客户端。

2.4组件执行位置和优先级设定

执行位置:Pre、Routing、After,分别代表后端服务调用前、后端服务调用中和后端服务调用完成后,相同位置的组件根据优先级决定执行的先后顺序。

2.5组件发布形式

组件打包成标准的Jar包,通过Admin管理界面上传发布。

三、如何快速开发一个组件

3.1基础工程搭建

1)采用IDEA或者Eclipse创建一个Maven的Java工程,工程名称建议为cmpt-开头,后面是具体的业务含义,如:cmpt-weixin-auth-token。

2)引入网关依赖包

参照cmpt-weixin-auth-token示例工程,将core和common的依赖加入进来;(需要将mvnreps目录下的内容加到本地mvn仓库)

不熟悉Maven配置也可以直接将lib下的包加入项目类路径。

3.2编写组件业务逻辑

1)继承AbstractCmpt抽象类,实现如下接口:
CmptResult execute(CmptRequest request, Map<String, FieldDTO> config)
具体说明请参考2.3,在此可以实现具体的业务逻辑。
2)如果需要网关内部的服务类,可以采用如下方式引入
private IAppService appService;


private IApiService apiService;


public 构造方法() {
this.appService = SpringContextHolder.getContext().getBean(IAppService.class);

this.apiService = SpringContextHolder.getContext().getBean(IApiService.class);

}


补充说明:
可以直接基于mpt-weixin-auth-token修改,效率更高。

3.3打包上传

采用Maven或者其它工具打出标准Jar包,通过Admin平台创建组件并上传Jar包,发布后API便可以绑定使用。

results matching ""

    No results matching ""