全部产品
云市场
云游戏

网关辅助类使用说明

更新时间:2019-09-09 15:12:19

实现拦截器功能

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

说明

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

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

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

image.png | center | 547x540

如上图所示,拦截器主要在以下几个点进行拦截:

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

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

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

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 成功。同时客户端去解析返回的数据,提取自定义错误码。