服务端
服务端API文档

回调鉴权

更新时间: 2022/08/18 09:26:59

功能介绍

  • 1、网易云信服务器可以通过消息抄送功能,将消息数据和事件通知等实时同步(云信发出HTTP-POST请求,用JSON格式的body来承载实际的内容)给开发者预设的服务器。请前往网易云信控制台 > 通信与视频(云信) > 选择对应的应用 > 消息抄送配置 > 设置接收抄送的服务器地址。抄送地址支持http和https,如果是https地址,开发者需要保证https证书的有效性,且配置时需携带http://或https://前缀。抄送地址支持IP和域名。

  • 2、输入有效的地址后,请点击确定按钮进行地址校验。校验的过程是云信服务器会往该地址post一条内容为空的请求(header见下方抄送HTTP Header定义,body为json格式,内容为空,即{}),如果在5秒内收到该地址返回HTTP 200状态码,则校验成功。若发现校验不成功,可以使用postman等工具辅助自测。

  • 3、地址校验通过后,可以勾选需要的抄送信息。部分功能需要联系商务经理申请开通后方可勾选,详见各自抄送类型的说明。完成后,当应用内发生对应的事件或产生对应的消息,开发者即可通过解析来自云信的post请求来获取内容。

  • 4、消息抄送的超时时间是5秒,如果在5秒内收到开发者服务器返回HTTP 200或HTTP 500状态码,则认为消息抄送成功,否则认为抄送失败。如果开发者在接收到消息之后,会做比较耗时的操作(例如DB入库等)的话,建议将该接口做成异步机制(例如可以将消息先存到MQ中),以免被网易云信判定为超时。若有特殊需求不能丢弃消息抄送,请联系商务经理开通高保障抄送。开通后,如果抄送失败,网易云信服务器将会尝试重新抄送一定次数(目前最多1000次)。如果开发者接收消息抄送的接口在一段时间内持续无法响应,网易云信服务器支持将最多50万条消息缓存下来,待开发者消息消息接收接口恢复后,手动提交任务重新进行抄送。

  • 5、考虑到网络环境的不稳定,为了确保开发者的消息接口能收到抄送的消息,网易云信可能会重复发送同一条消息,建议开发者对所收到的消息与事件通知进行一定的去重操作。

  • 6、在消息抄送服务中,post请求的header中的CheckSum = sha1(AppSecret + MD5 + CurTime), 其中AppSecret 、MD5、CurTime均为String类型。在验证数据是否在传输过程中被篡改时,需要计算验证MD5值是否被修改,以及计算验证CheckSum。AppSecret值为开发者的AppSecret(请勿与AppKey混淆), MD5值为根据request body计算出来的值, 即MD5 = md5(request body)。

  • 7、特别的,对于部分抄送类型(如API发消息、SDK发消息等),可以在发消息的参数里设置环境变量,服务器将根据环境抄送到不同的地址,环境和抄送地址的映射关系配置请联系商务经理。

  • 8、抄送的Content-Type为application/json,而非application/x-www-form-urlencoded,请注意区分解析方式。

回调地址设置

  • 登录云信控制台在选择开通云呼叫中心的应用,在云呼叫中心功能栏选择“号码管理”,在“消息回调地址配置”填写需要抄送消息的服务器地址

抄送HTTP Header定义

Header 参数说明
AppKey 开发者平台分配的appkey
CurTime 当前UTC时间戳,从1970年1月1日0点0 分0 秒开始到现在的毫秒数
CheckSum sha1(AppSecret + MD5 + CurTime)
MD5 md5(request body)
  • MD5值计算举例
String requestBody = "{}";
String MD5 = CheckSumBuilder.getMD5(requestBody);
  • CheckSum值计算举例
String AppSecret = "90u757h67n87"; //注意:此处是AppSecret,不是AppKey。
String MD5 = "9894907e4ad9de4678091277509361f7";
String CurTime = "1440570500855";  ////当前UTC时间戳,从197011000 秒开始到现在的毫秒数(String)
String CheckSum = CheckSumBuilder.getCheckSum(AppSecret, MD5, CurTime); //参考 接口概述 -> API checksum校验 部分

计算CheckSum的java代码举例如下

package com.netease.nim.route;

import com.alibaba.fastjson.JSONObject;

import com.netease.nim.route.CheckSumBuilder;

import org.apache.commons.io.IOUtils;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.stereotype.Controller;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RequestMethod;

import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;

import java.io.IOException;

@Controller

@RequestMapping(value = {"/route"})

public class RouteController {

   public static final Logger logger = LoggerFactory

           .getLogger(RouteController.class);

   // 需要改成自身应用的appSecret

   private final String appSecret = "7bb79g40f44j";

   @RequestMapping(value = {"/mockClient.action"}, method = {RequestMethod.POST})

   @ResponseBody

   public JSONObject mockClient(HttpServletRequest request)

           throws Exception {

       JSONObject result = new JSONObject();

       try {

           // 获取请求体

           byte[] body = readBody(request);

           if (body == null) {

               logger.warn("request wrong, empty body!");

               result.put("code", 414);

               return result;

           }

           // 获取部分request header,并打印

           String ContentType = request.getContentType();

           String AppKey = request.getHeader("AppKey");

           String CurTime = request.getHeader("CurTime");

           String MD5 = request.getHeader("MD5");

           String CheckSum = request.getHeader("CheckSum");

           logger.info("request headers: ContentType = {}, AppKey = {}, CurTime = {}, " +

                   "MD5 = {}, CheckSum = {}", ContentType, AppKey, CurTime, MD5, CheckSum);

           // 将请求体转成String格式,并打印

           String requestBody = new String(body, "utf-8");

           logger.info("request body = {}", requestBody);

           // 获取计算过的md5及checkSum

           String verifyMD5 = CheckSumBuilder.getMD5(requestBody);

           String verifyChecksum = CheckSumBuilder.getCheckSum(appSecret, verifyMD5, CurTime);

           logger.debug("verifyMD5 = {}, verifyChecksum = {}", verifyMD5, verifyChecksum);

           // TODO: 比较md5、checkSum是否一致,以及后续业务处理

           result.put("code", 200);

           return result;

       } catch (Exception ex) {

           logger.error(ex.getMessage(), ex);

           result.put("code", 414);

           return result;

       }

   }

   private byte[] readBody(HttpServletRequest request) throws IOException {

       if (request.getContentLength() > 0) {

           byte[] body = new byte[request.getContentLength()];

           IOUtils.readFully(request.getInputStream(), body);

           return body;

       } else

           return null;

   }

}




package com.netease.nim.route;

import java.security.MessageDigest;

public class CheckSumBuilder {

   // 计算并获取CheckSum

   public static String getCheckSum(String appSecret, String nonce, String curTime) {

       return encode("sha1", appSecret + nonce + curTime);

   }

   // 计算并获取md5值

   public static String getMD5(String requestBody) {

       return encode("md5", requestBody);

   }

   private static String encode(String algorithm, String value) {

       if (value == null) {

           return null;

       }

       try {

           MessageDigest messageDigest

                   = MessageDigest.getInstance(algorithm);

           messageDigest.update(value.getBytes());

           return getFormattedText(messageDigest.digest());

       } catch (Exception e) {

           throw new RuntimeException(e);

       }

   }

   private static String getFormattedText(byte[] bytes) {

       int len = bytes.length;

       StringBuilder buf = new StringBuilder(len * 2);

       for (int j = 0; j < len; j++) {

           buf.append(HEX_DIGITS[(bytes[j] >> 4) & 0x0f]);

           buf.append(HEX_DIGITS[bytes[j] & 0x0f]);

       }

       return buf.toString();

   }

   private static final char[] HEX_DIGITS = { '0', '1', '2', '3', '4', '5',

           '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };

}
此文档是否对你有帮助?
有帮助
去反馈
  • 功能介绍
  • 回调地址设置
  • 抄送HTTP Header定义
  • 计算CheckSum的java代码举例如下