欧珀莱麒麟CRM对外接口


一、数云对外接口技术方案

<p><strong>Chapter 1. 对接数云openapi步骤</strong> </p> <ul> <li>1.对接者先向数云申请serviceName和serviceSecret serviceName: 接口调用服务的身份标识,是一个固定的字符串常量,请向数云申请 serviceSecret:接口调用服务的身份密钥,请向数云申请。为确保安全,请妥善保管,不可泄露。</li> <li>2.对接者根据API定义编写客户端程序,可以使用任何技术语言编写。</li> <li>3.对接者与数云数据服务端进行接口联调,直至调试通过。</li> </ul> <p><strong>Chapter 2. 接口设计</strong> </p> <ul> <li>接口url: /{contextPath}/{version}{requestPath} 其中: 1) contextPath 是被调用服务的名称; 2) version 是被调用服务的版本信息; 3) requestPath是调用服务的请求路径。 示例如下: url: api.xxx.com/openapi/v2/wechat/member?memberId=5314115615&amp;memberType=tcbj contextPath: openapi version: v2 requestPath: /wechat/member</li> </ul> <p><strong>Chapter 3. 公共请求消息头</strong> </p> <ul> <li>1.所有请求头都必须包含 X-Caller-Service、 X-Caller-Timestamp、 X-Caller-Sign、 Content-Type</li> <li>2.说明</li> </ul> <table> <thead> <tr> <th style="text-align: left;">请求头(Header)</th> <th style="text-align: left;">说明</th> </tr> </thead> <tbody> <tr> <td style="text-align: left;">X-Caller-Service</td> <td style="text-align: left;">对应上文中的serviceName</td> </tr> <tr> <td style="text-align: left;">X-Caller-Timestamp</td> <td style="text-align: left;">时间戳.格式:yyyy-MM-dd HH:mm:ss,时区为GMT+8.如:2015-01-01 12:20:11</td> </tr> <tr> <td style="text-align: left;">X-Caller-Sign</td> <td style="text-align: left;">签名. 参考sign安全校验机制</td> </tr> <tr> <td style="text-align: left;">Content-Type</td> <td style="text-align: left;">只支持JSON格式. application/json; charset=utf-8</td> </tr> </tbody> </table> <p><strong>Chapter 4. sign安全校验机制</strong> </p> <ul> <li>1.各个服务通过gateway进行调用的时候,需要增加三个自定义的头信息:X-Caller-Service、XCaller-Timestamp、X-Caller-Sign.</li> <li>2.X-CallerSign是通过callerService、timestamp、contextPath、version、serviceSecret、restPath,按首字母排序后,进行md5加密获得的值,只需要将对应的名字做修改即可. Java版本代码如下: <pre><code class="language-java">import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.LinkedHashMap; import java.util.Map; import java.util.Set; public class SignConvertUtil { public static String generateSign(String callerService, String contextPath, String version,String timestamp, String serviceSecret, String requestPath) { String sign = ""; if (callerService == null || callerService.equals("") || contextPath == null ||contextPath.equals("") ||timestamp == null || timestamp.equals("") || serviceSecret == null || serviceSecret.equals("")) { return sign; } Map&lt;String, String&gt; map = new LinkedHashMap&lt;&gt;(); map.put("callerService", callerService); map.put("contextPath", contextPath); try { if (requestPath != null) { StringBuilder sb = new StringBuilder(); for(String part : requestPath.split("/")) { sb.append("/").append(URLEncoder.encode(part,"utf-8")); } map.put("requestPath", sb.toString().substring(1)); } map.put("timestamp", timestamp); map.put("v", version); sign = generateMD5Sign(serviceSecret, map); } catch (NoSuchAlgorithmException | UnsupportedEncodingException e) { e.printStackTrace(); return ""; } return sign; } private static String generateMD5Sign(String secret, Map&lt;String, String&gt; parameters) throws NoSuchAlgorithmException, UnsupportedEncodingException { MessageDigest md5 = MessageDigest.getInstance("MD5"); byte[]bytes=md5.digest(generateConcatSign(secret,parameters).getBytes("utf- 8")); return byteToHex(bytes); } private static String generateConcatSign(String secret, Map&lt;String, String&gt;parameters) { StringBuilder sb = new StringBuilder().append(secret); Set&lt;String&gt; keys = parameters.keySet(); for (String key : keys) { sb.append(key).append(parameters.get(key)); } return sb.append(secret).toString(); } private static String byteToHex(byte[] bytesIn) { StringBuilder sb = new StringBuilder(); for (byte byteIn : bytesIn) { String bt = Integer.toHexString(byteIn &amp; 0xff); if (bt.length() == 1) sb.append(0).append(bt); else sb.append(bt); } return sb.toString().toUpperCase(); } }</code></pre></li> </ul> <p><strong>Chapter 5. 响应状态码</strong> </p> <ul> <li>1xx:信息,请求收到,继续处理</li> <li>2xx:成功,行为被成功地接受、理解和采纳</li> <li>3xx:重定向,为了完成请求,必须进一步执行的动作</li> <li>4xx:客户端错误,请求包含语法错误或者请求无法实现</li> <li>5xx:服务器错误,服务器不能实现一种明显无效的请求 每种状态码都有不同含义,具体请参考HTTP状态码:<a href="http://developer.mozilla.org/zh-CN/docs/Web/HTTP/Status" title="HTTP 响应代码">HTTP 响应代码</a></li> </ul> <p><strong>Chapter 6. 错误返回格式</strong> </p> <ul> <li><code>HTTP状态非2xx时,错误返回统一为如下格式:</code></li> </ul> <table> <thead> <tr> <th style="text-align: left;">参数名</th> <th style="text-align: left;">类型</th> <th style="text-align: left;">是否必须</th> <th>说明</th> </tr> </thead> <tbody> <tr> <td style="text-align: left;">error_code</td> <td style="text-align: left;">String</td> <td style="text-align: left;">是</td> <td>错误码</td> </tr> <tr> <td style="text-align: left;">msg</td> <td style="text-align: left;">String</td> <td style="text-align: left;">是</td> <td>错误信息</td> </tr> </tbody> </table> <ul> <li> <p><code>示例:</code></p> <pre><code>{ "error_code" : "opai.invalid-parameter", "msg" : "参数不合法" } </code></pre> </li> <li><code>错误码说明:</code></li> </ul> <table> <thead> <tr> <th style="text-align: left;">错误码</th> <th style="text-align: left;">说明</th> </tr> </thead> <tbody> <tr> <td style="text-align: left;">opai.invalid-parameter</td> <td style="text-align: left;">参数不合法</td> </tr> </tbody> </table>

页面列表

ITEM_HTML