全部产品

网关辅助类使用说明

本文对网关中用到的相关辅助类,包括拦截器类、MobileRpcHolder,以及网关错误码的使用进行说明。

实现拦截器功能

拦截器只适用于非 HTTP 类型服务。

mobilegw-unify-spi-adapter.jar 实际上是通过 Java 的反射调用业务方法,即OperatioinType 所指定的方法。在方法调用的过程中,业务方可以实现 SPI 包中定义的拦截器,从而实现扩展。

网关的 SPI 包定义了两个拦截器:AbstractMobileServiceInterceptor 抽象类和 MobileServiceInterceptor 接口。

AbstractMobileServiceInterceptor

MobileServiceInterceptor 主要提供了四个方法,分别是 beforeInvokeafterInvoke(分为两种:一种入参为业务返回的 Object;另一种入参为 Object 转成的 JSON string)、throwsInvokegetOrder

image.png | center | 547x540

如上图所示,拦截器主要在以下三种情况下进行拦截:

  • 方法调用前:即 beforeInvoke方法,该方法有返回值。一旦该方法的返回值不为空,那么网关认定拦截成功,将会跳过剩余拦截器的 beforeInvoke 方法,同时跳过调用业务方的方法,直接进入拦截器的 afterInvoke 方法。

  • 方法调用后: 即 afterInvoke 方法。afterInvoke 有两种,一种入参为 Object,即业务方返回的对象,该方法没有返回值,所有的拦截器的该方法都会执行;另一种入参为 Object 转成的 JSON string,该方法可以改变传入的 JSON 数据并返回。一旦返回值不为空,那么网关认定拦截成功,后续的拦截器将被忽略。

  • 方法出现异常:即 throwsInvoke 方法。该方法没有返回值,所有拦截器的该方法都会被执行。在业务方出现异常时会被调用。

MobileServiceInterceptor

MobileServiceInterceptor 继承了框架的 Ordered 接口,因此,业务方实现的拦截器还可以通过实现 getOrder方法指定执行顺序,设置的数值越小,执行的优先级越高;设置的数值越大,执行的优先级越低。

使用示例

  1. 编码自己的拦截器类,继承 AbstractMobileServiceInterceptor 类,或者实现MobileServiceInterceptor 接口。

         
    1. public class MyInterceptor implements MobileServiceInterceptor {
    2. /*
    3. 参数说明
    4. method:即业务方的方法(@OperatioinType 定义的方法)
    5. args: 一个对象数组,即业务方方法的传入参数,传入参数个数即等于数组大小。
    6. 使用时业务方根据需要进行类型转换。
    7. bean: 即业务方的接口实例。
    8. 返回值说明:
    9. Object:可以在拦截器中返回数据,一旦返回值不为空,则网关认为已被拦截,就不会再调用业务方法
    10. 同时,直接跳过其他拦截器的 beforeInvoke 方法,执行拦截器中的 afterInvoke 方法。
    11. */
    12. @Override
    13. public Object beforeInvoke(Method method, Object[] args, Object target) {
    14. //Do Something
    15. return null;
    16. }
    17. /*
    18. *参数说明
    19. *returnValue: 业务方法返回的对象
    20. * 其它参数同上
    21. */
    22. @Override
    23. public void afterInvoke(Object returnValue, Method method, Object[] args, Object target) {
    24. //注意:这里入参是业务方返回的 Object
    25. }
    26. @Override
    27. public String afterInvoke(String returnJsonValue, Method method, Object[] args, Object target) {
    28. //注意:这里入参是由业务方返回的 object,转换而成的 JSON 格式的 string
    29. //可以返回新的 JSON 数据
    30. return null;
    31. }
    32. @Override
    33. public void throwsInvoke(Throwable t, Method method, Object[] args, Object target) {
    34. }
    35. @Override
    36. public int getOrder() {
    37. //最高级(数值最小)和最低级(数值最大)。
    38. return 0;
    39. }
    40. }
  2. 发布实现的类 MyInterceptor,成为 Bean。

    • Spring Boot:
      直接在该类加注解 @service
             
      1. @service
      2. public class MyInterceptor implements MobileServiceInterceptor{}
    • Spring:
      在配置的 xml 文件声明。
             
      1. <bean id="myInterceptor" class="com.xxx.xxx.MyInterceptor"/>

MobileRpcHolder 辅助类

MobileRpcHoldermobilegw-unify-spi-adapter.jar 中提供的一个静态辅助类,该类定义了一个请求过程中的相关信息,最主要的定义如下:

   
  1. Map<String, String> session 保存请求的 session
  2. Map<String, String> header 保存请求的头部相关信息
  3. Map<String, String> context 保存网关调用的上下文信息
  4. String operationType 保存此次请求的 operationType

在业务方的服务(即 OperationType)被调用之前,SPI 服务会根据网关转发的请求 MobileRpcRequest 去设置 MobileRpcHolder 这些信息。在调用业务方服务之后这些信息会被清除。

MobileRpcHolder 的生命周期为整个服务的调用过程,调用后清除。

业务方也可以根据需要去设置这些信息,这些信息会在调用业务的服务过程中一直存在,在调用过程中业务服务可以获取这些信息。具体的设置可以通过拦截器,在方法调用前后动态地修改 MobileRpcHolder 中保存的信息。

以下通过例子说明 MobileRpcHolder 如何使用。

使用示例

这里以修改和获取 session 为例。

  1. 修改 session。
    创建拦截器,具体过程参考上面的拦截器示例。下面以在方法调用前拦截为例:

         
    1. @Override
    2. public Object beforeInvoke(Method method, Object[] args, Object target) {
    3. Map<String, String> session = MobileRpcHolder.getSession();
    4. session.put("key_test", "value_test");
    5. MobileRpcHolder.setSession(session);
    6. }

    这样就能修改 MobileRpcHolder 中的 session 信息。

  2. 获取 session。
    业务方在自己定义的服务中可以获取 session 信息。

         
    1. @OperationType("com.alipay.account.query")
    2. public String mock2(String s) {
    3. Map<String, String> session = MobileRpcHolder.getSession();
    4. }

    其他信息(如 header、context)的修改和获取方式同上。

         
    1. // 获取 header 所有信息
    2. Map<String,String> headers = MobileRpcHolder.getHeaders();
    3. // 这里上下文信息指的是请求中的上下文信息
    4. Map<String,String> context = MobileRpcHolder.getRequestCtx();
    5. // 获取 OperationType
    6. String opt = MobileRpcHolder.getOperationType();

使用网关错误码

移动网关有自己的一套错误码规范,详见 网关结果码说明

需要注意 BizException 6666,此错误是业务出现异常后,网关会抛出的异常。

如果想要在出现具体错误时,返回其他错误码,可以通过抛出 RpcException(ResultEnum resultCode) 来控制 RPC 层的错误,比如 resultCode=1001,会返回给客户端“没有权限访问”。

代码示例

   
  1. @Override
  2. public String mock2(String s) throws RpcException {
  3. try{
  4. test();
  5. }catch (Exception e){
  6. throw new RpcException(IllegalArgument);
  7. }
  8. return "11111111";
  9. }

自定义错误码

如果想使用自定义错误码,那么在调用业务方法时不能往外抛异常。

业务方法只要出现异常,就会返回状态码 6666。同时客户端收到该状态码,即认为服务出错,不会去解析业务返回的数据。客户端只有在接收到 1000 状态码时,才会去解析返回的数据。

具体做法是,服务端和客户端约定好具体的错误码,然后在调用业务方法时捕获(catch)所有的异常,将自定义错误码放在返回的数据中。这样业务就算出异常,网关也会返回 1000 成功。同时客户端去解析返回的数据,提取自定义错误码。