快速入门 =============== .. _餐链: http://www.mealcome.com/ .. _basic_concepts: 基本概念 --------------- .. include:: concept/client_id.rst .. _system_params: 系统级输入参数 -------------------- API参数共由两部分组成,系统级参数指所有由 `餐链`_ 提供的API所必须的参数,应用级参数是指对应API所需的参数。所有编码统一采用UTF-8 .. include:: common/system_params.rst .. note:: 不论接口是GET、POST、PUT、DELETE等HTTP方法,系统级参数都是以URL参数的方式传递的。 .. _request_process: 接口调用流程 ------------------ 针对每个接口的请求流程如下: 1. 根据功能需求确认接口。 2. 确认请求参数。 3. 计算签名。 4. 拼接请求地址。 5. 针对不同接口,指定 ``request_body`` 、``content_type`` 和请求方法(GET/POST/DELETE/PUT)。 .. note:: 关于request_body的说明: * 在某些POST或PUT等请求中,需要把json格式的参数体放在请求体(request_body)中。request_body不直接参与签名(sign)计算,但是这时候要先根据request_body生成bodySign参数,生成算法:Hex(SHA-256(request_body+client_secret)),Hex字符大写,得到bodySign。而bodySign需要参与签名(sign)的计算。 * "Content-Type"为"application/json;charset:utf-8;" .. _gen_sign: 签名计算 --------------------- 签名计算规则 ^^^^^^^^^^^^^^^^^^^^^^^^^ 1. 对参数名称进行排序得到 ``字符串1`` 将所有参数(sign除外)按照参数名的字母顺序排序,并用 ``&`` 连接:: accessToken=93f37d1bcf5b2f022cebc0bc3efd9342&client_id=ae674b84-f266-4785-b37b-228c044be967&nonce=6B8C311E537B7C5B0D5E5EECEFE0BF941A262AC24A3744C249D9994DD55A3120×tamp=1497583267 .. note:: 计算sign时需要注意的以下几点: * 除特别申明不需要计算的参数之外(如包含在请求体中的参数),其他参数都需要包含在 ``字符串1`` 中 * 在某些POST或PUT等请求中,需要把json格式的参数体放在请求体(request_body)中。request_body不直接参与签名(sign)计算,但是这时候要先根据request_body生成bodySign参数,生成算法:Hex(SHA-256(request_body+client_secret)),Hex字符大写,得到bodySign。而bodySign需要参与签名(sign)的计算。所以 ``字符串1`` 应该为:: accessToken=93f37d1bcf5b2f022cebc0bc3efd9342&bodySign=013A660AC36F14BAE42EC538F7E42E7E7DCEBD1C383F380D6A9C132098C2188F&client_id=ae674b84-f266-4785-b37b-228c044be967&nonce=6B8C311E537B7C5B0D5E5EECEFE0BF941A262AC24A3744C249D9994DD55A3120×tamp=1497583267 * "Content-Type"为"application/json;charset:utf-8;" 2. 计算 ``字符串2`` 按照请求url + ? + ``字符串1`` + client_secret的顺序进行连接,得到 ``字符串2`` :: /stores?accessToken=93f37d1bcf5b2f022cebc0bc3efd9342&client_id=ae674b84-f266-4785-b37b-228c044be967&nonce=6B8C311E537B7C5B0D5E5EECEFE0BF941A262AC24A3744C249D9994DD55A3120×tamp=14975832675ea0ac4f-90f5-4136-81ab-615cbca49f34 3. 计算签名 对 ``字符串2`` 计算SHA-256哈希,得到签名(把字节转换成Hex,签名必须大写):: 0B79D9513EB643B678607D7DC1B1676E2EA8B6D177C664F1B21A1D5ABF25EEEA 4. 拼接请求URL 将得到的签名赋给sign作为HTTP请求的URL参数:: http://openapi.mealcome.cn/stores?accessToken=93f37d1bcf5b2f022cebc0bc3efd9342&client_id=ae674b84-f266-4785-b37b-228c044be967&nonce=0CA432789B15DEDF98431DE829B1A15BB64CA05AFCCFED17A994D975E92AB43A×tamp=1497583611&sign=0B79D9513EB643B678607D7DC1B1676E2EA8B6D177C664F1B21A1D5ABF25EEEA 5. 签名示例 接下来将使用例子示例签名的计算过程。 查询商户的所有门店基础信息(数据均为假数据,只为演示签名过程,以实际调用结果为准):: url: /store client_id: ae674b84-f266-4785-b37b-228c044be967 client_secret: 5ea0ac4f-90f5-4136-81ab-615cbca49f34 nonce: 6B8C311E537B7C5B0D5E5EECEFE0BF941A262AC24A3744C249D9994DD55A3120 timestamp: 1497583267 accessToken: 93f37d1bcf5b2f022cebc0bc3efd9342 用于计算签名的字符串为:: /store?accessToken=93f37d1bcf5b2f022cebc0bc3efd9342&client_id=ae674b84-f266-4785-b37b-228c044be967&nonce=6B8C311E537B7C5B0D5E5EECEFE0BF941A262AC24A3744C249D9994DD55A3120×tamp=1497583267 请求url为:: http://openapi.mealcome.com/store?accessToken=93f37d1bcf5b2f022cebc0bc3efd9342&client_id=ae674b84-f266-4785-b37b-228c044be967&nonce=0CA432789B15DEDF98431DE829B1A15BB64CA05AFCCFED17A994D975E92AB43A×tamp=1497583611&sign=40EE0C1E5C6D267B1FBD25904652D5AE25C80D7A83B032570FB57632D4D99D9F response body里的数据为(此为演示数据,实际调用结果不同): .. code-block:: json { "code": 200, "data": { "id": 1, "name": "格林店", "code": "1", "pinyin": null, "address": null, "longitude": null, "latitude": null, "note": null, "cityName": "", "proviceName": "", "tenantId": 1 }, "message": null, "error": null } .. note:: * URL路径中的参数作为url一部分已参与签名计算,为了避免冗余,不再作为request params的一部分进行签名计算。 +-------------+----------------+--------------+----------------------------------------+ | 名称 | 类型 | 可空 | 描述 | +=============+================+==============+========================================+ | code | int | 非空 | 返回的调用状态码 | +-------------+----------------+--------------+----------------------------------------+ | data | object | 可空 | 返回的业务数据 | +-------------+----------------+--------------+----------------------------------------+ | message | string | 可空 | 描述业务非正常处理原因 | +-------------+----------------+--------------+----------------------------------------+ | error | string | 可空 | 描述业务非正常处理的错误码 | +-------------+----------------+--------------+----------------------------------------+ .. note:: string的类型为字符类型(包含所有中英文字符,utf8编码),单个字符其长度都统一为1,字节数以实际存储为准。 .. note:: 目前签名验证比较常见的问题: * 生成的时间戳在请求当前的时间前后15分钟范围之外 * 签名重复使用 * 时间戳是以秒为单位,也就是10位的时间戳。容易弄错成13位的时间戳 * POST方式的请求需要考虑中文乱码的情况,可能我方接到body中的中文是乱码的,从而导致签名计算跟实际情况不匹配 .. _code_description: code码 --------------------- 状态码含义:: 具体详情见下表。 +-----------+-------------------------------------------------------+ | code | 类型 | +===========+=======================================================+ | 200 | 业务正常处理 | +-----------+-------------------------------------------------------+ | 400 | 参数异常 | +-----------+-------------------------------------------------------+ | 500 | 业务异常 | +-----------+-------------------------------------------------------+ | 600 | 未知异常,未检查异常 | +-----------+-------------------------------------------------------+ | 700 | 应用程序错误,已检查异常 | +-----------+-------------------------------------------------------+ | 800 | 框架调用异常 | +-----------+-------------------------------------------------------+ 访问异常错误返回 ^^^^^^^^^^^^^^^^^^^^ .. _error_codes: .. code-block:: json { "timestamp": 1495094151006, "status": 500, "error": "Internal Server Error", "exception": "BusinessException", "message": "javax.servlet.ServletException: BusinessException{errorCode='50003001', errorMessage='该随机字符串无效!'}", "path": "/units" } .. _api_test_info: 接口测试信息 ---------------------- 餐链开放平台请求的基础地址为:: http://120.26.164.191:8092 .. _api_test_merchant_info: 商家测试 ^^^^^^^^^^^^^^^^^ 餐链提供了以下体验店信息以供接口开发测试 python测试程序 ^^^^^^^^^^^^^^^^^ .. code-block:: python # python 3.0以上版本 import http.client import urllib.parse import time import uuid import hashlib headers = {"Content-type": "application/json;charset:utf-8;", "Content-Encoding": "UTF-8"} host = "openapi.mealcome.cn" clientId = "8fa2bc6957b24a8b8bf3dfcbe3a34c81" clientSecret = "79753124b23147fb82309b0ed9e14533" accessToken = "7c89d63940654f93988639532ce2c447" def base(): mytime = int(time.time()) base_params = {"client_id": clientId, "accessToken": accessToken, "timestamp": str(mytime), "nonce": uuid.uuid1()} return base_params def get(url, params): base_params = base() if params is not None: urlParams = dict(base_params, **params) else: urlParams = base_params # 排序 urlParams = sorted(urlParams.items(), key=lambda dict: dict[0]) # 创建签名字符串并生成签名 url = url + "?" + urllib.parse.urlencode(urlParams, False, "", "utf-8", None, urllib.parse.quote) md = (urllib.parse.unquote(url) + clientSecret).encode("utf-8") sign = hashlib.sha256(md).hexdigest() # 请求接口 request = url + "&sign=" + str(sign).upper() print("http://" + host + request) httpClient = http.client.HTTPConnection(host) httpClient.request("GET", request) response = httpClient.getresponse() print(response.read()) if __name__ == '__main__': get("/store", None) params = {"begin": "2017-11-04 10:00:00", "end": "2017-11-05 11:00:00"} get("/material/changes", params) .. _api_prod_info: 接口生产环境信息 ------------------------- 餐链开放平台请求的基础地址为:: http://openapi.mealcome.cn 接口特别说明 ---------------------- * 所有涉及到地址位置坐标的,均使用的是百度坐标系 接口更新日志 ----------------------- 随着使用方需求变更已经系统升级,OpenAPI接口可能会发生改变。 相应的改变会记录在此文档内。