接入规范
更新时间:2018-04-13 12:08:06 更新人员:叶洋

文档状态:完成
摘要
本文阐述接口对接规范,数据收发方式,数据处理约定
-
前提准备规则
☆ 本系统API接口使用了商户(merch)验证,只有通过了商户验证的接口请求才是合法的请求。
★ 每个商户在系统内会有属于该商户的独立的接口权限划分,该商户未授权的接口将禁止访问。
☆ 系统内会对商户进行有效期进行管理,如若当前时间超出商户有效期范围,接口将禁止访问。
★ 系统可以为接口访问发起地址IP进行白名单管理,如若商户设置了白名单,接口只能在该白名单IP下才能访问,其它IP地址下接口将禁止访问。
☆ 接口访问还必须传递接口版本号,只有版本号验证通过才能正常访问接口。
-
接口基础地址
规范使用接口基础地址为:
本地开发测试:
baseurl: "http://ecapi.local/api/"
线上测试地址:
baseurl: "http://dev3srv.echuan56.com/api/"
线上正式地址:
baseurl: "************************"
-
允许的请求方式
本系统允许以下的请求方式:
OPTION: ref接口只检查接口存不存在能不能够访问,不执行接口,用在自动调用时第一次请求
GET: 获取数据(集)时的动作
POST: 提交数据时的动作,常用于需提交产生新数据时的请求
PUT: 提交更新的数据内容时的动作,常用于需更新数据时的请求
PATCH: 提交更新数据时的动作,更新时有特殊限制
DELETE: 提交删除数据的请求动作,包含真删和假删(回收)
一个接口限定只允许使用一种方式。
注意:系统不存在同一个接口允许几种请求方式同时存在,接口方式错误将导致接口访问错误或接口不存在错误。
-
允许的接口版本号
目前开放的接口版本号:
x-api-ver: "1.0"
接口版本号应该置于请求头RequestHeaders中,参数名为:x-api-ver
-
传递商户密钥
本系统接口基于商户身份识别后进而调用。每个商户拥有独立的商户密钥,密钥在系统内是唯一的、长期不变的。
商户密钥如果泄露,商户管理者可以申请更换商户密钥,商户系统对接本系统接口时也需更换为新的密钥。
商户密钥的传递方式同版本号一样,置于请求头RequestHeaders内传递。参数名为:x-api-key ,例如:
x-api-key: "2Io8J*************************UL" // 32位字符串密钥
请注意:一旦商户密钥错误,将无法访问接口。
-
接口地址和参数路由
文档中的地址都是不带基础地址的,需要自行拼接到基础地址上。接口地址如果出现“<”、“>”、“:”标识符,则出现了路由带参数,其中的参数名为标识中的字符串,值为匹配值。
带参路由举例如下:
// 冒号(:)路由:
标注接口地址:GET "member/:uid$" // 接口携带了一个参数uid
// 假设uid="c24w2c5w6b1a2ycw",则接口请求地址为:
请求接口地址:GET "member/c24w2c5w6b1a2ycw"
// 尖括号(<、>)路由:
标注接口地址:GET "member/<uid>$" // 接口携带了一个参数uid
// 假设uid="c24w2c5w6b1a2ycw",则接口请求地址为:
请求接口地址:GET "member/c24w2c5w6b1a2ycw"
-
用户标识和设备标识
在限定需要用户登录后才能访问的接口请求中,需要传递用户标识才允许访问。
用户标识的获取方法,可以使用登录接口的返回数据来取到用户标识码,即用户Token,响应参数名为:Access-Token。注意用户登录使用了单点登录控制。
接口传递用户Token的方式,同样是带参于请求头RequestHeaders中,参数名为:access-token ,举例:
access-token: "c31e839bd1c5a9771064bc27002f3a098cf72726" // 用户token为40位字符串值
在一些非必传(不需要验证)用户登录的接口中传递了用户token,依然会取到token对应的用户作为该接口的已登录操作用户。
系统为PC、移动设备等规划了设备标识,为了避免不同设备之间同一用户发生单点登录效应而采取了一种设备标识分离控制方法,使得同一用户可以同时在PC和移动设备上登录,该参数可以不用传递。参数名为:device-identy,默认值为:web。可列举参数:
device-identy: "web" // 默认值 web 标识,可用于PC设备
"ios" // 使用了 ios 标识,用于苹果系统设备
"android" // 使用了 android 标识,用于安卓系统设备
"wap" // 使用了 wap 标识,用于 H5 端
"smartpr" // 使用了 smartpr 标识,用于小程序端
-
请求参数与签名
本系统接口提供规则验证的参数表,未通过验证的参数将反馈错误提示。
本系统可验证多层结构参数,子参数为数组(Array)或对象(Object)时亦可。
仅带参数的提交请求方法可使用:
headers['Content-Type'] = "application/json; charset=utf-8"
如果带文件上传,则需要设置为:
headers['Content-Type'] = "multipart/form-data"
传递的参数需要进行签名。注意是包含路由参数在内一起签名,签名完成后将签名带入参数中一起提交。
paramData.signature: "44744bce6153a696f9cda31df49d6180"
签名方法可参考本章第十小节。
-
接口返回数据格式标准
接口访问返回数据统一为 Json 对象格式。在返回对象的第一层拥有 3 个对象属性。形如:
{
code: 0, // 返回码 为0时执行成功,其它请查阅返回码定义
msg: '接口访问成功!', // 提示文字
data: ... // 返回数据 数据类型不固定:[obj/arr/str/num/...]
}
另外需要注意,在某些特殊的接口中会返回特定的响应头参数,比如登录接口的返回响应头中就包含了登录成功用户的token值,用户可以拿到这个响应头的参数值进行本地存储及使用。
-
调用封装函数
JS封装(Vue-Axios)
数据签名:
/**
* 数据签名加密
* @param paramList
* @returns {string}
*/
export function autograph (paramList) {
const currDay = new Date().toLocaleDateString().replace(/\/(\d)\//, '/0$1/').replace(/\/(\d)$/, '/0$1').replace(/\//g, '')
let param = []
let mvkey = ''
let mvval = ''
for (let i in paramList) {
if (typeof i !== 'string' && typeof i !== 'undefined') {
i = i.toString()
}
if (typeof paramList[i] !== 'string' && typeof paramList[i] !== 'undefined') {
paramList[i] = paramList[i].toString()
}
mvkey = i === undefined ? '' : i.trim()
mvval = paramList[i] === undefined ? '' : paramList[i].trim()
if (mvkey !== '' && mvval !== '') {
param.push(`${mvkey}=${mvval}`)
}
}
param.push(`merch_key=${XAPIKEY}`)
param.sort((a, b) => {
return a > b ? 1 : -1
})
let cssstr = param.join('&')
let signstr = md5(cssstr)
signstr = md5(`${signstr}.${XAPIKEY}`)
signstr = md5(signstr + currDay)
return signstr
}
调用函数:
/**
* axios 自定义封装
* @param url
* @param types 判断是否公共接口调用
* @param configs
* @returns {Promise}
*/
export function apirq (url, configs, types) {
let configsDefalut = {
baseURL: API,
method: 'get',
data: {},
urlparams: [] // 自定义路由参数,根据参数进行替换路由
}
let typeDefault = []
if (types) {
typeDefault = types.split(',')
}
configs = Object.assign(Object.assign({}, configsDefalut), configs)
if (configs.data['signature'] !== undefined) {
delete configs.data['signature']
}
configs.data['signature'] = autograph(configs.data)
for (let t of configs.urlparams) {
url = url.replace(`:${t}`, configs.data[t]).replace(`<${t}>`, configs.data[t])
delete configs.data[t]
}
delete configs.urlparams
configs.url = url
let headers = ACCESSHEADER
// 如果是公共接口,则不需要access-token
const actoken = sessionStorage.getItem('accessToken') // 判断是否已经存在accessToken
if (typeDefault.indexOf('noauth') === -1 && actoken !== null) {
headers['access-token'] = actoken
}
headers['Content-Type'] = 'application/json; charset=utf-8'
configs.headers = headers
if (configs.method === 'get') {
configs.params = configs.data
delete configs.data
}
return new Promise((resolve, reject) => {
axios(configs).then((response) => {
for (let i = 0; i < typeDefault.length; i++) {
switch (typeDefault[i]) {
case 'login':
sessionStorage.setItem('accessToken', response.headers['access-token'])
break
}
}
resolve(response.data)
}).catch((e) => {
reject(e)
})
})
}