回调事件接口设计解决方案

1、背景

很多业务系统,对将自身业务批量提交至第三方服务,交由第三方业务系统进行处理,处理结束后,会异步地通过回调事件,将处理结果回写给当前业务系统。本文对事件回调接口设计提出解决方案。

2、接口设计

21、三方回调请求接口设计

三方系统,将处理结果,批量通过接口发送至当前系统;

1)一般采用post请求,json格式,数组形式进行发送;

2)增设重发机制,一旦发送失败,变长定期重发;

3)设定重发上限,避免过度无效请求;

4)在未接到接收方返回情况下,不执行下次重发请求,避免接收方短时间内不断重复接受数据,导致内存过载;

5)如果时间允许,可增设手动不发的web页面功能。

2.3、接受方接口设计

1)接受方,接受数据,使用MQ进行异步化,在未处理的情况下,异步响应三方,接受成功。

2)接受方接受到数据,推送至消息队列MQ;

3)在数据处理服务器,创建监听,接受MQ消息,进行异步处理。

优点:

① 快速将数据转移,避免内存压力;

② 将数据处理业务,转移至对应的数据处理服务器,功能解耦;

③ 避免同步处理,一旦异常,未做好异常处理机制,导致回写整体失败,或部分失败的情况。

3、安全机制

3.1、增加签名机制

一般情况下是对json串中部分数据计算出签名,作为参数发送出去,接受方依照相同的算法对约定的部分数据进行计算,验证签名参数值,如下举例:

package com.ddyunf.cloud.common.utils;

import sun.misc.BASE64Encoder;

import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

/**
 * Created by Liuxd on 2018-06-21.
 */
public class SignatureUtil {

    /**
     * 利用MD5进行加密
     *
     * @param str 待加密的字符串
     * @return 加密后的字符串
     * @throws NoSuchAlgorithmException     没有这种产生消息摘要的算法
     * @throws UnsupportedEncodingException
     */
    public static String EncoderByMd5(String str) {
        BASE64Encoder base64en = new BASE64Encoder();
        String newstr = null;
        try {
            //确定计算方法
            MessageDigest md5 = MessageDigest.getInstance("MD5");
            //加密后的字符串
            newstr = base64en.encode(md5.digest(str.getBytes("utf-8")));
        } catch (Exception e) {
            e.printStackTrace();
        }

        return newstr;
    }

    public static String getMD5_32Byte(String str) {
        try {
            // 生成一个MD5加密计算摘要
            MessageDigest md = MessageDigest.getInstance("MD5");
            // 计算md5函数
            md.update(str.getBytes());
            // digest()最后确定返回md5 hash值,返回值为8为字符串。因为md5 hash值是16位的hex值,实际上就是8位的字符
            // BigInteger函数则将8位的字符串转换成16位hex值,用字符串来表示;得到字符串形式的hash值
            String md5=new BigInteger(1, md.digest()).toString(16);
            //BigInteger会把0省略掉,需补全至32位
            return fillMD5(md5);
        } catch (Exception e) {
            throw new RuntimeException("MD5加密错误:"+e.getMessage(),e);
        }
    }

    public static String fillMD5(String md5){
        return md5.length()==32?md5:fillMD5("0"+md5);
    }

    public static void main(String[] args) throws Exception {
        String str = "abcdef";
        String strAfterCode = EncoderByMd5(str);
        System.out.println("加密前:" + str);
        System.out.println("加密后:" + strAfterCode);
        System.out.println("加密后长度:" + strAfterCode.length());

        String str2 = "lee81g";
        System.out.println("md5:"+ getMD5_32Byte(str2));
        System.out.println("length:"+ getMD5_32Byte(str2).length());

    }

}

3.2、对数据进行加密

     避免数据明码显示,避免数据明码传送。

package com.ddyunf.cloud.teletraffic.third.util;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import java.security.Key;
import java.security.SecureRandom;

/**
 * 用Des算法加密和解密的
 *
 */
public class DESDateUtils {

	private static Key key;  
    private static String KEY_STR="keySecret";//此值约定双方达成一致
      
    static{  
        try  
        {  
            KeyGenerator generator = KeyGenerator.getInstance("DES");  
            SecureRandom secureRandom=SecureRandom.getInstance("SHA1PRNG");  
            secureRandom.setSeed(KEY_STR.getBytes());  
            generator.init(secureRandom);  
            key = generator.generateKey();  
            generator=null;  
        }  
        catch (Exception e)  
        {  
            throw new RuntimeException(e);  
        }  
    }  
      
    /** 
     * 对字符串进行加密,返回BASE64的加密字符串 
     * <功能详细描述> 
     * @param str 
     * @return 
     * @see [类、类#方法、类#成员] 
     */  
    public static String getEncryptString(String str){  
        BASE64Encoder base64Encoder = new BASE64Encoder();  
//        System.out.println(key);  
        try  
        {  
            byte[] strBytes = str.getBytes("UTF-8");  
            Cipher cipher = Cipher.getInstance("DES");  
            cipher.init(Cipher.ENCRYPT_MODE, key);  
            byte[] encryptStrBytes = cipher.doFinal(strBytes);  
            return base64Encoder.encode(encryptStrBytes);  
        }  
        catch (Exception e)  
        {  
            return "-1";
        }  
          
    }  
      
    /** 
     * 对BASE64加密字符串进行解密 
     * <功能详细描述> 
     * @param str 
     * @return 
     * @see [类、类#方法、类#成员] 
     */  
    public static String getDecryptString(String str){  
        BASE64Decoder base64Decoder = new BASE64Decoder();  
        try  
        {  
            byte[] strBytes = base64Decoder.decodeBuffer(str);  
            Cipher cipher = Cipher.getInstance("DES");  
            cipher.init(Cipher.DECRYPT_MODE, key);  
            byte[] encryptStrBytes = cipher.doFinal(strBytes);  
            return new String(encryptStrBytes,"UTF-8");  
        }  
        catch (Exception e)  
        {  
        	 return "-1";
        }  
          
    }

    public static void main(String[] args) {
        String str = "abc123";

        String afterEncode = getEncryptString(str);

        String afterDecode = getDecryptString(afterEncode);

        System.out.println(str);
        System.out.println(afterEncode);
        System.out.println(afterDecode);
    }
}

3.3、防火墙白名单配置

发送方与接收方服务器,开启防火墙,在各防火墙中配置彼此服务器的出口ip

以上是本人,在设计和开发中的总结,不到之处还请留言提出宝贵意见,希望共同交流,将回调事件接口处理的更完善。

 

你可能感兴趣的:(解决方案)