mPaaS-RPC 拦截器各种场景下的使用指南
Posted mPaaS
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了mPaaS-RPC 拦截器各种场景下的使用指南相关的知识,希望对你有一定的参考价值。
mPaaS 移动网关服务(Mobile Gateway Service,简称 MGS)作为 mPaas 最重要的组件之一,连接了移动客户端与服务端,简化了移动端与服务端的数据协议和通讯协议,从而能够显著提升开发效率和网络通讯效率。
在我们日常运维过程中发现,很多用户在使用客户端RPC组件的时候,有很多不同场景的诉求,比如拦截请求添加业务请求标记,免登,返回结果模拟,异常处理,限流等。
本文旨在介绍通过利用RPC提供的拦截器机制,通过不同实际场景的描述,供业务参考使用。
RPC调用原理
RpcDemoClient client = MPRpc.getRpcProxy(RpcDemoClient.class);
// 设置请求
GetIdGetReq req = new GetIdGetReq();
req.id = "123";
req.age = 14;
req.isMale = true;
// 发起 rpc 请求
String response = client.getIdGet(req);
public <T> T getRpcProxy(Class<T> clazz) {
LogCatUtil.info("RpcFactory", "clazz=[" + clazz.getName() + "]");
return Proxy.newProxyInstance(clazz.getClassLoader(), new Class[]{clazz}, new RpcInvocationHandler(this.mConfig, clazz, this.mRpcInvoker));
}
RpcService rpcService = getMicroApplicationContext().findServiceByInterface(RpcService.class.getName());
rpcService.addRpcInterceptor(OperationType.class, new CommonInterceptor());
拦截器原理
preHandle场景
1. 全局添加业务自定义请求header
@Override
public boolean preHandle(Object proxy,
ThreadLocal<Object> retValue,
byte[] retRawValue,
Class<?> aClass,
Method method,
Object[] args,
Annotation annotation,
ThreadLocal<Map<String, Object>> threadLocal)
throws RpcException {
//Do something...
RpcInvocationHandler handler = (RpcInvocationHandler) Proxy.getInvocationHandler(proxy);
handler.getRpcInvokeContext().addRequestHeader("header", "headerCustom");
return true;
}
2. 阻断当前请求rpc流程
@Override
public boolean preHandle(Object proxy,
ThreadLocal<Object> retValue,
byte[] retRawValue,
Class<?> aClass,
Method method,
Object[] args,
Annotation annotation,
ThreadLocal<Map<String, Object>> threadLocal)
throws RpcException {
//Do something...
String operationType = getOperationType(aClass, method, args);
if ("operationType1".equals(operationType)) {
boolean isLogin = false;
if (!isLogin) {
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
@Override
public void run() {
Toast.makeText(LauncherApplicationAgent.getInstance().getApplicationContext(),
"当前未登录,请登录", Toast.LENGTH_SHORT).show();
}
});
// 返回给上层调用登录失败的异常,上层做业务处理
throw new RpcException(RpcException.ErrorCode.CLIENT_LOGIN_FAIL_ERROR, "login fail.");
}
}
return true;
}
private String getOperationType(Class<?> aClass, Method method, Object[] args) {
if (aClass == null || null == method) return "";
OperationType operationType = method.getAnnotation(OperationType.class);
return operationType == null ? "" : operationType.value();
}
postHandle场景
1. 拦截接口返回
@Override
public boolean postHandle(Object proxy,
ThreadLocal<Object> threadLocal,
byte[] retRawValue,
Class<?> aClass,
Method method,
Object[] args,
Annotation annotation) throws RpcException {
//Do something...
// 场景:修改服务端返回的数据,比如mock数据,或者修改服务端数据
String operationType = getOperationType(aClass, method, args);
LoggerFactory.getTraceLogger().debug(TAG, "postHandle:" + operationType);
if ("operationType1".equals(operationType)) {
String value = JSON.parse(retRawValue).toString();
LoggerFactory.getTraceLogger().debug(TAG, "postHandle 原始返回" + value);
String mockData = "{"img":"imgPath","User":{"name":"我是mock的数据","age":18}}";
Object mockObj = JSON.parseObject(mockData, method.getReturnType());
threadLocal.set(mockObj);
return true;
}
return true;
}
private String getOperationType(Class<?> aClass, Method method, Object[] args) {
if (aClass == null || null == method) return "";
OperationType operationType = method.getAnnotation(OperationType.class);
return operationType == null ? "" : operationType.value();
}
exceptionHandle场景
1. 异常统一处理
@Override
public boolean exceptionHandle(Object proxy, ThreadLocal<Object> retValue, byte[] bytes, Class<?> aClass, Method method, Object[] objects,
RpcException rpcException, Annotation annotation) throws RpcException {
String operationType = getOperationType(aClass, method, objects);
if (RpcException.ErrorCode.CLIENT_LOGIN_FAIL_ERROR == rpcException.getCode()
&& "operationType1".equals(operationType)) {
// 1. 去免登
hasLogin = true;
// 2. 免登后在帮上层重发请求,免登操作对上层业务无感知
try {
LoggerFactory.getTraceLogger().debug(TAG, "exceptionHandle. Start resend rpc begin " + operationType);
// 重发请求
Object object = method.invoke(proxy, objects);
retValue.set(object);
LoggerFactory.getTraceLogger().debug(TAG, "exceptionHandle. Start resend rpc success");
return false;
} catch (Throwable e) {
LoggerFactory.getTraceLogger().error(TAG, "resend rpc occurs illegal argument exception", e);
throw new RpcException(RpcException.ErrorCode.CLIENT_HANDLE_ERROR, e + "");
}
}
return true;
}
H5场景
1. 获取H5请求的接口名称和入参
var params = [{
"_requestBody":{"userName":"", "userId":0}
}]
var operationType = 'alipay.mobile.ic.dispatch'
AlipayJSBridge.call('rpc', {
operationType: operationType,
requestData: params,
headers:{}
}, function (result) {
console.log(result);
});
public boolean preHandle(Object o, ThreadLocal<Object> threadLocal, byte[] bytes, Class<?> aClass, Method method, Object[] objects, Annotation annotation, ThreadLocal<Map<String, Object>> threadLocal1) throws RpcException {
String operationType = getOperationType(aClass, method, objects);
if ("alipay.client.executerpc".equals(operationType)) {
// H5的rpc名称
String rpcName = (String) objects[0];
// 入参
String req = (String) objects[1];
LoggerFactory.getTraceLogger().debug(TAG, "operationType:" + rpcName + " " + req);
} else {
// Native的rpc
}
LoggerFactory.getTraceLogger().debug(TAG, "operationType:" + operationType);
return true;
}
- END -
以上是关于mPaaS-RPC 拦截器各种场景下的使用指南的主要内容,如果未能解决你的问题,请参考以下文章
Android智能手机中各种音频场景下的audio data path
flink standalone 部署模式且不能使用 hdfs 场景下的各种问题及其应对方案
Android 逆向函数拦截 ( ARM 架构下的插桩拦截 | 完整代码示例 )