本文对网关中用到的相关辅助类,包括拦截器类、MobileRpcHolder,以及网关错误码的使用进行说明。
实现拦截器功能
拦截器只适用于非 HTTP 类型服务。
mobilegw-unify-spi-adapter.jar
实际上是通过 Java 的反射调用业务方法,即OperatioinType
所指定的方法。在方法调用的过程中,业务方可以实现 SPI 包中定义的拦截器,从而实现扩展。
网关的 SPI 包定义了两个拦截器:AbstractMobileServiceInterceptor
抽象类和 MobileServiceInterceptor
接口。
AbstractMobileServiceInterceptor
MobileServiceInterceptor
主要提供了四个方法,分别是 beforeInvoke
、afterInvoke
(分为两种:一种入参为业务返回的 Object;另一种入参为 Object 转成的 JSON string)、throwsInvoke
和 getOrder
。
如上图所示,拦截器主要在以下三种情况下进行拦截:
方法调用前:即
beforeInvoke
方法,该方法有返回值。一旦该方法的返回值不为空,那么网关认定拦截成功,将会跳过剩余拦截器的beforeInvoke
方法,同时跳过调用业务方的方法,直接进入拦截器的afterInvoke
方法。方法调用后: 即
afterInvoke
方法。afterInvoke
有两种,一种入参为 Object,即业务方返回的对象,该方法没有返回值,所有的拦截器的该方法都会执行;另一种入参为 Object 转成的 JSON string,该方法可以改变传入的 JSON 数据并返回。一旦返回值不为空,那么网关认定拦截成功,后续的拦截器将被忽略。方法出现异常:即
throwsInvoke
方法。该方法没有返回值,所有拦截器的该方法都会被执行。在业务方出现异常时会被调用。
MobileServiceInterceptor
MobileServiceInterceptor
继承了框架的 Ordered
接口,因此,业务方实现的拦截器还可以通过实现 getOrder
方法指定执行顺序,设置的数值越小,执行的优先级越高;设置的数值越大,执行的优先级越低。
使用示例
编码自己的拦截器类,继承
AbstractMobileServiceInterceptor
类,或者实现MobileServiceInterceptor
接口。public class MyInterceptor implements MobileServiceInterceptor { /* 参数说明 method:即业务方的方法(@OperatioinType 定义的方法) args: 一个对象数组,即业务方方法的传入参数,传入参数个数即等于数组大小。 使用时业务方根据需要进行类型转换。 bean: 即业务方的接口实例。 返回值说明: Object:可以在拦截器中返回数据,一旦返回值不为空,则网关认为已被拦截,就不会再调用业务方法 同时,直接跳过其他拦截器的 beforeInvoke 方法,执行拦截器中的 afterInvoke 方法。 */ @Override public Object beforeInvoke(Method method, Object[] args, Object target) { //Do Something return null; } /* *参数说明 *returnValue: 业务方法返回的对象 * 其它参数同上 */ @Override public void afterInvoke(Object returnValue, Method method, Object[] args, Object target) { //注意:这里入参是业务方返回的 Object } @Override public String afterInvoke(String returnJsonValue, Method method, Object[] args, Object target) { //注意:这里入参是由业务方返回的 object,转换而成的 JSON 格式的 string //可以返回新的 JSON 数据 return null; } @Override public void throwsInvoke(Throwable t, Method method, Object[] args, Object target) { } @Override public int getOrder() { //最高级(数值最小)和最低级(数值最大)。 return 0; } }
发布实现的类
MyInterceptor
,成为 Bean。Spring Boot:直接在该类加注解
@service
。@service public class MyInterceptor implements MobileServiceInterceptor{}
Spring:在配置的
xml
文件声明。<bean id="myInterceptor" class="com.xxx.xxx.MyInterceptor"/>
MobileRpcHolder 辅助类
MobileRpcHolder
是 mobilegw-unify-spi-adapter.jar
中提供的一个静态辅助类,该类定义了一个请求过程中的相关信息,最主要的定义如下:
Map<String, String> session 保存请求的 session
Map<String, String> header 保存请求的头部相关信息
Map<String, String> context 保存网关调用的上下文信息
String operationType 保存此次请求的 operationType
在业务方的服务(即 OperationType
)被调用之前,SPI 服务会根据网关转发的请求 MobileRpcRequest
去设置 MobileRpcHolder
中的信息。在调用业务方服务之后这些信息会被清除。
MobileRpcHolder
的生命周期为整个服务的调用过程,调用后清除。
业务方也可以根据需要去设置这些信息,这些信息会在调用业务的服务过程中一直存在,在调用过程中业务服务可以获取这些信息。具体的设置可以通过拦截器,在方法调用前后动态地修改 MobileRpcHolder
中保存的信息。
以下通过例子说明 MobileRpcHolder
如何使用。
使用示例
这里以修改和获取 session 为例。
修改 session。 创建拦截器,具体过程参考上面的拦截器示例。下面以在方法调用前拦截为例:
@Override public Object beforeInvoke(Method method, Object[] args, Object target) { Map<String, String> session = MobileRpcHolder.getSession(); session.put("key_test", "value_test"); MobileRpcHolder.setSession(session); }
这样就能修改
MobileRpcHolder
中的 session 信息。获取 session。 业务方在自己定义的服务中可以获取 session 信息。
@OperationType("com.alipay.account.query") public String mock2(String s) { Map<String, String> session = MobileRpcHolder.getSession(); }
其他信息(如 header、context)的修改和获取方式同上。
// 获取 header 所有信息 Map<String,String> headers = MobileRpcHolder.getHeaders(); // 这里上下文信息指的是请求中的上下文信息 Map<String,String> context = MobileRpcHolder.getRequestCtx(); // 获取 OperationType String opt = MobileRpcHolder.getOperationType();
使用网关错误码
移动网关有自己的一套错误码规范,详见 网关结果码说明。
需要注意 BizException 6666
,此错误是业务出现异常后,网关会抛出的异常。
如果想要在出现具体错误时,返回其他错误码,可以通过抛出 RpcException(ResultEnum resultCode)
来控制 RPC 层的错误,比如 resultCode=1001
,会返回给客户端“没有权限访问”。
代码示例
@Override
public String mock2(String s) throws RpcException {
try{
test();
}catch (Exception e){
throw new RpcException(IllegalArgument);
}
return "11111111";
}
自定义错误码
如果想使用自定义错误码,那么在调用业务方法时不能往外抛异常。
业务方法只要出现异常,就会返回状态码 6666。同时客户端收到该状态码,即认为服务出错,不会去解析业务返回的数据。客户端只有在接收到 1000 状态码时,才会去解析返回的数据。
具体做法是,服务端和客户端约定好具体的错误码,然后在调用业务方法时捕获(catch)所有的异常,将自定义错误码放在返回的数据中。这样即使业务出现异常,网关也会返回 1000 成功。同时客户端去解析返回的数据,提取自定义错误码。