当前位置: 首页 > backend >正文

基于Java 实现 IM 业务回调

1.什么是业务回调

image.png

2.腾讯云回调的类型

功能角度

  • 在线状态回调

  • 资料关系链回调

  • 单聊消息回调

  • 群组系统回调

处理角度

  • 事件发生之前回调:回调的主要目的在于让 App 后台可以干预该事件的处理逻辑,即时通信 IM 会根据回调返回码确定后续处理流程(例如发送群消息之前回调)

  • 事件发生之后通知:回调的主要目的在于让 App 后台实现必要的数据同步,即时通信 IM 忽略回调返回码(例如群组成员退群之后通知)

3.业务执行之前回调

业务执行之前的回调是可以干涉业务是否继续执行的,但是业务之后回调不行,所以这里单独说一下

image.png

4.腾讯云即时通讯IM对于业务回调

介绍

image.png

回调协议

图示

image.png

回调示例请求示例
POST /?SdkAppid=888888&CallbackCommand=Group.CallbackAfterNewMemberJoin&contenttype=json&ClientIP=$ClientIP&OptPlatform=$OptPlatform HTTP/1.1
Host: www.example.com
Content-Length: 337
{"CallbackCommand": "Group.CallbackAfterNewMemberJoin", "GroupId": "@TGS#2J4SZEAEL", "Type": "Public", "JoinType": "Apply", "Operator_Account": "leckie", "NewMemberList": [{"Member_Account": "jared"}, {"Member_Account": "tommy"}]
}
回调应答示例

HTTP/1.1 200 OK
Server: nginx/1.7.10
Date: Fri, 09 Oct 2015 02:59:55 GMT
Content-Length: 75
{"ActionStatus": "OK", "ErrorInfo": "", "ErrorCode": 0
}

回调超时时间及重试

image.png

事件发生之前回调超时的处理策略

image.png

回调安全考虑

介绍

即时通信 IM 同时支持 HTTP/HTTPS 回调,其中 HTTPS 回调需要在App 后台的 WebServer 配置 CA 机构签发的证书或即时通信 IM 免费签发的证书

安全性问题
  • HTTP 是明文传输,数据的保密性无法保证,建议使用HTTPS

  • 无法验证回调请求是否真正来自于即时通信 IM

解决方案
  • 支持回调鉴权(推荐)

  • 支持 HTTPS 双向认证

支持回调鉴权

image.png

支持HTTPS回调

image.png

回调不通的常见原因

image.png

5.实践

推荐使用AOP来实现回调

/*** @description: 回调注解* @author:sgy* @date: 2023-08-22*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Callback {/*** 回调业务命令*/CallbackCommandEnum command();/*** 是否存在之后回调* @return*/boolean after() default true;/*** 是否存在之前回调* @return*/boolean before() default false;/*** appId* @return*/String appId();
}

/*** @description:业务回调切面* @author:sgy* @date: 2023-08-22*/
@Aspect
@Slf4j
@Component
public class CallbackAspect {@Resourceprivate ICallbackService callbackService;/*** 使用AOP在方法之前拦截请求*/@Around("@annotation(cn.sgy.im.system.service.aop.callback.Callback)")public Object around(ProceedingJoinPoint joinPoint) throws Throwable {// 根据连接点获取方法上的Callback注解Callback callback = getCallback(joinPoint);// 业务之前的回调Result result = executeBeforeCallback(callback, joinPoint.getArgs()[0]);// 校验是否允许继续执行,如果允许继续执行才执行业务if (checkBeforeResult(result)) {Object proceed = joinPoint.proceed();// 业务执行后回调executeAfterCallback(callback, proceed);return proceed;} else {return null;}}/*** 业务执行回调*/private void executeAfterCallback(Callback callback, Object obj) {// 基本属性获取boolean after = callback.after();CallbackCommandEnum command = callback.command();int appId = Convert.toInt(callback.appId());// 如果存在之后回调if (after) {callbackService.afterCallback(appId, command.getCommand(), obj);}}/*** 检查之前回调结果是否允许继续执行* - 结果不符合格式允许继续执行* - 结果允许继续执行* - 结果不允许继续执行* - 是NULL允许继续执行* - 等等** @param result* @return*/private boolean checkBeforeResult(Result result) {return true;}/*** 执行之前回调** @param callback*/private Result executeBeforeCallback(Callback callback, Object obj) {// 基本属性获取boolean before = callback.before();CallbackCommandEnum command = callback.command();int appId = Convert.toInt(callback.appId());// 如果存在之前回调if (before) {return callbackService.beforeCallback(appId, command.getCommand(), obj);}return null;}/*** 根据连接点获取方法上的Callback注解** @param joinPoint* @return*/private Callback getCallback(ProceedingJoinPoint joinPoint) throws Exception {MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();Method targetMethod = joinPoint.getTarget().getClass().getDeclaredMethod(methodSignature.getName(), methodSignature.getMethod().getParameterTypes());return targetMethod.getAnnotation(Callback.class);}}

 

/*** @description:回调服务* @author:sgy* @date: 2023-08-22*/
public interface ICallbackService {/*** 业务之前回调* @param appId appId* @param callbackCommand 回调类型* @param obj 回调具体的数据* @return*/Result beforeCallback(Integer appId,String callbackCommand,Object obj);/*** 业务之后回调* @param appId appId* @param callbackCommand 回调类型* @param obj 回调具体的数据* @return*/void afterCallback(Integer appId,String callbackCommand,Object obj);
}


/*** @description:业务回调实现类,不完善* @author:sgy* @date: 2023-08-22*/
@Service
@Slf4j
public class CallbackServiceImpl implements ICallbackService {@Resourceprivate TcpServiceCallbackConfig tcpServiceCallbackConfig;@Resourceprivate RestTemplate restTemplate;@Overridepublic Result beforeCallback(Integer appId, String callbackCommand, Object obj) {try {HttpHeaders headers = new HttpHeaders();headers.setContentType(MediaType.APPLICATION_JSON);HttpEntity<String> requestEntity = new HttpEntity<String>(JSONUtil.toJsonStr(obj), headers);ResponseEntity<Result> resultResponseEntity = restTemplate.exchange(tcpServiceCallbackConfig.getCallbackUrl(), HttpMethod.POST, requestEntity, Result.class);return resultResponseEntity.getBody();} catch (Exception e) {log.error("callback 之前 回调{} : {}出现异常 : {} ", callbackCommand, appId, e);return Results.success();}}@Overridepublic void afterCallback(Integer appId, String callbackCommand, Object obj) {
//        shareThreadPool.submit(() -> {
//            try {
//                httpRequestUtils.doPost(appConfig.getCallbackUrl(),Object.class,builderUrlParams(appId,callbackCommand),
//                        jsonBody,null);
//            }catch (Exception e){
//                logger.error("callback 回调{} : {}出现异常 : {} ",callbackCommand , appId, e.getMessage());
//            }
//        });}
}
http://www.xdnf.cn/news/10186.html

相关文章:

  • Java 之殇:从中流砥柱到“被温柔替代”
  • LeetCode Hot100(动态规划)
  • 04-redis-分布式锁-edisson
  • yum安装nginx后无法通过服务方式启动
  • 企业知识库问答系统避坑指南:检索优化与生成一致性解决方案
  • [ctfshow web入门] web80
  • 2.测试项目启动和研读需求文档
  • js 动画库、2048核心逻辑、面试题add[1][2][3]+4
  • Datatable和实体集合互转
  • 华锐视点助力,虚拟旅游绽放更璀璨光彩​
  • 图书管理系统的设计与实现
  • 北京大学肖臻老师《区块链技术与应用》公开课:06-BTC-网络
  • canoe 排查配置相关【graphics,capl】
  • Python基本运算符
  • python装饰器
  • DSP处理数字信号做什么用的?
  • Unsafe.putOrderedInt与Volatile
  • 驱动灯珠芯片LT3743手册理解
  • phpmyadmin
  • RTOS:启动调度器的作用(含源码逐行解读)
  • 微信小店推客系统达人用户管理的数据支持和便利
  • 【仿生机器人】Alice计划——仿生机器人需求
  • ABB HIEE300690R0001 AR C093 AE01 励磁调节器 PCB板特价
  • 第六十一节:深度学习-使用 OpenCV DNN 模块
  • 江科大SPI串行外设接口hal库实现
  • Linux 1.0.4
  • [硬件选型篇] 一文解决常用5V转3.3V电路选型困难(包括各选型的优缺点、纹波、效率等)
  • DAY 15 复习日
  • SpringBoot整合Flowable【08】- 前后端如何交互
  • jq处理日志数据