# 网关对接规范

# 网关说明

  • 网关地址:

    • dev 环境地址:http://dev-gapis-base.igancao.com/oapi
    • prod环境地址:https://gapis-base-outer.igancao.com/oapi
  • 请求QPS限制:
    普通账号的QPS=5,如果超过次此阀值的请求,会被网关阻挡,下一秒后恢复。如需提高QPS阀值,请联系商务人员进行调整。

  • ip白名单限制:
    测试环境无限制,生产环境必须提供ip白名单,上限10个ip。
    说明:设置白名单的目的是防止内部开发人员,如果泄露密钥或者发生离职后,也能保证开放平台只响应业务端服务器发起的请求。会拒绝从ip白名单以外的地方发送请求,为保证业务系统安全,生产系统必须设置白名单。

  • 接口授权范围:
    接入的应用商,只能对授权业务范围内的接口进行通信,如越界请求请求将会被拒绝。

# 网关通信与传输

传输层采用两层结构,header中的签名数据,与body业务数据体,请求方式通过https的post方式实现传输,不支持get方式。其中body数据体采用json协议进行定义,并且在传输时使用ase128进行双向对称加密。并且所有数据采用utf-8字符集。

# Header部分

Header中必须包含以下头参数:

  • CONTENT-TYPE: application/json;charset=utf-8
  • USER-AGENT: appname/[ver] ([system info; nnn; nnn])
    例如:php_curl/1.10.0 (Apache/2.2.19 (Win64) PHP/5.4.9)
  • AK: 17位定长(由服务商提供)
    例如:OU022A29A2937PAR9
  • UTC-TIMESTAMP: 时间戳(秒)
    例如:1667351441
    说明:为Unix 纪元(格林威治时间 1970 年 1 月 1 日 00:00:00)到当前时间的秒数
    注意:调用发起方的时差与甘草服务器的误差必须在 正负3600秒内。否则请求将被拒绝。
  • NOISE: 为8位[a-zA-z0-9]随机字符,请保持15分钟内不会重复
    例如:12D34aq9
  • SIGNATURE: 签名;对post的body体的签名值,长度为40个字节
    算法:sha1($sBody + $sTimestemp + $sNoise + $sSK);
    说明:$sBody为未AES加密前的原始json数据包
    注意:每个签名15分钟内只能使用一次,如果重复会被截止回放逻辑阻挡请求。

# 加密传输(双向)

在进行公网数据通信时,需要使用aes128(AES-128-ECB)对body体进行对称加密,加解密时使用的key为sk需要向服务商获取(每个ak账号对应唯一的一个sk,sk为定长16字符的字符串)。
【注意】 加密与签名无关,加密只在传输时使用。

  • 加密过程:对待发送的数据加密,加密后的值base64_encode后,放入Post请求体内发送。
  • 解密过程:收到数据后,对数据包使用 base64_decode 后再进行aes128解密算法。

# 模拟数据测试校对

以下参数用于核对本地的签名算法是否正确:

AK: OU022A29A2937PAR9
SK: 8313cdff54f0ff14
Timestamp: 1668425289
Noise: 12345678
Body: {"package":"igc_base.ai.tongue","class":"ASYNC_GET_TONGUE_TASK","tongue_code":"TG022B01920029ZC2"}
Signature: 4d068cbc9e52fa56c6cdd0fd2ca419be0757656d

加密后发送的body数据包的值:

Qxb5jIBWK0YJhmo71ADAfYX2EyusuXRBD1TcwPJIprmF3zRYs7wJPQk8foJ9ONbXHXYDYPASFy3jSB82QK8NGARrUhDm++dZF/xxjkRSwkfAFF60LFlqlrrmIDpFjZ/ogfAFLaiZb/t7hLyedK9+Hw==

可使用以上信息在本地模拟校验签名算法以及加密通信发送的数据包是否正确,如果Signature与发送的body数据包体内容完全一致,表示能够正常与网关进行通信。

  • aes128(AES-128-ECB)对body体进行对称加密 php代码块参考样例
class Aes128SecurityService{
    /**
     * 加密处理
     * @param string $string 需要加密的字符串
     * @param string $key 密钥
     * <li>注意:key只有前16位参与加密</li>
     * @return null|string(base64)
     */
    public static function encrypt(string $string, string $key): ?string {
        // openssl_encrypt 加密不同Mcrypt,对秘钥长度要求,超出16加密结果不变
        $sOutBuf = openssl_encrypt($string, 'AES-128-ECB', $key, OPENSSL_RAW_DATA);
        if (false !== $sOutBuf){
            return base64_encode($sOutBuf);
        }else{
            return null;
        }
    }
    /**
     * 解密处理
     * @param string $string 需要解密的字符串(base64)
     * @param string $key 密钥
     * <li>注意:key只有前16位参与解密</li>
     * @return null|string
     */
    public static function decrypt(string $string, string $key): ?string {
        $sOutBuf = openssl_decrypt(base64_decode($string), 'AES-128-ECB', $key, OPENSSL_RAW_DATA);
        if (false !== $sOutBuf){
            return $sOutBuf;
        }else{
            return null;
        }
    }
}

# 网关出入参传输协议

网关的接口路由,使用body中的 package与class参数进行,网关地址保持固定不变。接口的出入参协议有固定格式。【注意】接口body体中的key区分大小写(json标准协议key都应该小写),传参时务必注意。详细说明如下:

# 入口协议基础结构

每个请求体必定包含以下key结构,其中package与class为接口的路由标识(可在各自业务的接口文档中找到参数值)。

{
    "package":"public_platform.ground_sys.base_info.pull",
    "class":"GET_STORE_BASE_INFO"
}

# 接口文档的据属性说明

接口协议中每个字段的定义分为字段说明字段类型说明( []中的内容为字段属性定义),定义中 required 表示为必填字段,sometimes 表示为或填字段,未出现 required 表示非必填字段,其余类型根据属性名称一般能自行理解,请详见每个接口的出入参说明。

例如:[required | string | digits:11] 表示:必填,字符串,11位定长数字

  • 样例代码
{
    "phone":"手机号 [required | string | digits:11]",
    "name":"名字 [required | string | min:2 | max:8]",
    "age":"年龄 [sometimes | integer | between:1,90]",
    "sex":"性别 [sometimes | in:M男,F女,N未知]",
    "u_type":"用户类型 [sometimes | in: 1:网站, dct:医生(注册:广告), 10:1号粉剂, t_t, $4]",
    "money":"金额 [sometimes | numeric | min:0.01 | max:99]",
    "id_code":"身份证号码 [sometimes | alpha_num | size:18]",
    "statuc_code":"状态码(定长6位数字或字母) [sometimes | alpha_num | fixed:6]",
    "tag":"标签数组(注意是数组) [sometimes | array | max:3]",
    "email":"邮箱地址 [sometimes | email]",
    "ipv4":"ipv4地址 [sometimes | ip]",
    "callback_url":"回调地址 [sometimes | active_url]",
    "web_url":"网址 [sometimes | url]",
    "filter":{
        "st_dt":"开始时间 [sometimes | date_format:Y-m-d | before_or_equal:filter.ed_dt]",
        "ed_dt":"终止日期 [sometimes | date_format:Y-m-d]"
    },
    "package":"igc_biz.example.template",
    "class":"CHECK_IN_PARAM_ROLE"
}

# 其常用数据类型说明如下:

  • 数据类型string字符串,integer整形,numeric带小数的数字,email邮箱地址,ip地址,url网址,active_url有效网址(带dns有效性检查)
  • 字符扩展alpha仅全数为字母字串,alpha_num仅允许字母、数字, alpha_dash仅允许字母、数字、破折号(-)以及底线(_),digits纯数字定长长度
  • 日期类型date_format日期格式
  • 检查约束before_or_equal大于或等于某个key的对象值
  • 枚举控制in仅支持列表红的枚举(注意因为或数字开头的部分,后面的文字为枚举值的解释,如果枚举值与解释内容无法区分时会用:区分)
  • 区间控制:(适用于string指长度;integerdouble时指区间范围):between:min,max区间,min最小值,max最大值,size指定长位数

以上涉及长度的约束参数,均为字的方式计数,即:一个全角中文与一个英文或者数字,都属于一个字

# 出参基础结构

  • result 字段内包的内容为kv结构,均由应用层返回。
  • status 内为固定结构由框架系统层定义;其中 status.code 是字符串类型。排查接口请求时,业务方可以将status.trace_id提供给技术人员,以便跟踪排查接口的请求数据,加快排查速度。
{
    "result":{
        "key":"val"
    },
    "status":{
        "code":"status code [string | min:3 | max:5]",
        "msg":"status message [string]",
        "runtime":"api runtime(ms) [double]",
        "trace_id": "1903141001025191549"
    }
}

# 出参的返回状态码

出参的状态码分为两个级别,000~999表示系统级错误,一般只会出现在接口对接时或者内部服务故障时才会遇到;00000~99999表示业务级错误,由每个接口的应用服务确定,此类错误码会存在重复,详见各自的接口文档。

【注意】当 status.code = "00000" 表示业务请求处理成功,若非这个值,可以收集 status.msg值返给前端或记录日志,一般遇到错误时都会有明确的提示信息,如不清楚时,可联系技术支持人员排查。

  • 系统级错误信息如下
901 ⇒ Received protocol packets can not be resolved.(收到的协议包无法解析)
915 ⇒ Refused to replay the request.(拒绝重放请求)
916 ⇒ Idempotent request interception.(幂等请求拦截)
917 ⇒ package and class node values do not exist.(package或class节点值不存在)
918 ⇒ API interface class not found.(api接口服务类未找到)
919 ⇒ API interface file not found.(api接口文件未找到)
920 ⇒ The returned value of the unregistered state.(未注册的返回状态值)
921 ⇒ API interface services no output result set.(api接口服务无输出结果集)
930 ⇒ Invalid characters in package.(package中存在无效字符)
940 ⇒ Interface has invalid.(此接口已经废除,停止服务)
997 ⇒ Application layer processing timeout.(应用层处理超时)
998 ⇒ Invalid Workspace directory.(接口的workspace实例工作目录不存在)
999 ⇒ There is no post and get data.(不存在post或get数据)

# sdk下载

# 说明

我们根据不同的开发语言环境封装了sdk文件,使用这个方式可加快网关对接进度。请下载对应的开发语言环境进行调试。

sdk详细的使用方式请参考代码中的备注信息。

go get -u github.com/zxyphp/gancao_openapi