翻页bug 在接口文档中应规范参数的取值区间 接口规范

 

<?php
$a=array("red","green","blue","yellow","brown");
print_r(array_slice($a,28));

 

Array
(
)

 

例如每页总条数50;

而前端从1开始传页码,数据总条数为10,后端将offset计算为50,则返回空数据,前端无数据显示;

PHP: array_slice - Manual http://php.net/manual/en/function.array-slice.php

array_slice

(PHP 4, PHP 5, PHP 7)

array_slice — Extract a slice of the array

Description

array array_slice ( array $array , int $offset [, int $length = NULL [, bool $preserve_keys = FALSE ]] )

array_slice() returns the sequence of elements from the array array as specified by the offset and length parameters.

Parameters

 

array

The input array.

offset

If offset is non-negative, the sequence will start at that offset in the array. If offset is negative, the sequence will start that far from the end of the array. Note that the offset denotes the position in the array, not the key.

length

If length is given and is positive, then the sequence will have up to that many elements in it. If the array is shorter than the length, then only the available array elements will be present. If length is given and is negative then the sequence will stop that many elements from the end of the array. If it is omitted, then the sequence will have everything from offset up until the end of the array.

preserve_keys

Note that array_slice() will reorder and reset the integer array indices by default. You can change this behaviour by settingpreserve_keys to TRUE. String keys are always preserved, regardless of this parameter.

Return Values

Returns the slice. If the offset is larger than the size of the array then returns an empty array.

 

<?php
print(max(1,3));
?>

 

【微信支付】微信小程序支付开发者文档 https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_1

应用场景

商户在小程序中先调用该接口在微信支付服务后台生成预支付交易单,返回正确的预支付交易后调起支付。

接口链接

URL地址:https://api.mch.weixin.qq.com/pay/unifiedorder

是否需要证书

请求参数

字段名变量名必填类型示例值描述
小程序ID appid String(32) wxd678efh567hg6787 微信分配的小程序ID
商户号 mch_id String(32) 1230000109 微信支付分配的商户号
设备号 device_info String(32) 013467007045764 自定义参数,可以为终端设备号(门店号或收银设备ID),PC网页或公众号内支付可以传"WEB"
随机字符串 nonce_str String(32) 5K8264ILTKCH16CQ2502SI8ZNMTM67VS 随机字符串,长度要求在32位以内。推荐随机数生成算法
签名 sign String(32) C380BEC2BFD727A4B6845133519F3AD6 通过签名算法计算得出的签名值,详见签名生成算法
签名类型 sign_type String(32) MD5 签名类型,默认为MD5,支持HMAC-SHA256和MD5。
商品描述 body String(128) 腾讯充值中心-QQ会员充值

商品简单描述,该字段请按照规范传递,具体请见参数规定

商品详情 detail String(6000)   商品详细描述,对于使用单品优惠的商户,改字段必须按照规范上传,详见“单品优惠参数说明”
附加数据 attach String(127) 深圳分店 附加数据,在查询API和支付通知中原样返回,可作为自定义参数使用。
商户订单号 out_trade_no String(32) 20150806125346 商户系统内部订单号,要求32个字符内,只能是数字、大小写字母_-|*且在同一个商户号下唯一。详见商户订单号
标价币种 fee_type String(16) CNY 符合ISO 4217标准的三位字母代码,默认人民币:CNY,详细列表请参见货币类型
标价金额 total_fee Int 88 订单总金额,单位为分,详见支付金额
终端IP spbill_create_ip String(16) 123.12.12.123 APP和网页支付提交用户端ip,Native支付填调用微信支付API的机器IP。
交易起始时间 time_start String(14) 20091225091010 订单生成时间,格式为yyyyMMddHHmmss,如2009年12月25日9点10分10秒表示为20091225091010。其他详见时间规则
交易结束时间 time_expire String(14) 20091227091010

订单失效时间,格式为yyyyMMddHHmmss,如2009年12月27日9点10分10秒表示为20091227091010。订单失效时间是针对订单号而言的,由于在请求支付的时候有一个必传参数prepay_id只有两小时的有效期,所以在重入时间超过2小时的时候需要重新请求下单接口获取新的prepay_id。其他详见时间规则

建议:最短失效时间间隔大于1分钟

订单优惠标记 goods_tag String(32) WXG 订单优惠标记,使用代金券或立减优惠功能时需要的参数,说明详见代金券或立减优惠
通知地址 notify_url String(256) http://www.weixin.qq.com/wxpay/pay.php 异步接收微信支付结果通知的回调地址,通知url必须为外网可访问的url,不能携带参数。
交易类型 trade_type String(16) JSAPI 小程序取值如下:JSAPI,详细说明见参数规定
商品ID product_id String(32) 12235413214070356458058 trade_type=NATIVE时(即扫码支付),此参数必传。此参数为二维码中包含的商品ID,商户自行定义。
指定支付方式 limit_pay String(32) no_credit 上传此参数no_credit--可限制用户不能使用信用卡支付
用户标识 openid String(128) oUpF8uMuAJO_M2pxb1Q9zNjWeS6o trade_type=JSAPI,此参数必传,用户在商户appid下的唯一标识。openid如何获取,可参考【获取openid】。

举例如下:

<xml>
   <appid>wx2421b1c4370ec43b</appid>
   <attach>支付测试</attach>
   <body>JSAPI支付测试</body>
   <mch_id>10000100</mch_id>
   <detail><![CDATA[{ "goods_detail":[ { "goods_id":"iphone6s_16G", "wxpay_goods_id":"1001", "goods_name":"iPhone6s 16G", "quantity":1, "price":528800, "goods_category":"123456", "body":"苹果手机" }, { "goods_id":"iphone6s_32G", "wxpay_goods_id":"1002", "goods_name":"iPhone6s 32G", "quantity":1, "price":608800, "goods_category":"123789", "body":"苹果手机" } ] }]]></detail>
   <nonce_str>1add1a30ac87aa2db72f57a2375d8fec</nonce_str>
   <notify_url>http://wxpay.wxutil.com/pub_v2/pay/notify.v2.php</notify_url>
   <openid>oUpF8uMuAJO_M2pxb1Q9zNjWeS6o</openid>
   <out_trade_no>1415659990</out_trade_no>
   <spbill_create_ip>14.23.150.211</spbill_create_ip>
   <total_fee>1</total_fee>
   <trade_type>JSAPI</trade_type>
   <sign>0CB01533B8C1EF103065174F50BCA001</sign>
</xml>

注:参数值用XML转义即可,CDATA标签用于说明数据不被XML解析器解析。

返回结果

字段名变量名必填类型示例值描述
返回状态码 return_code String(16) SUCCESS

SUCCESS/FAIL

此字段是通信标识,非交易标识,交易是否成功需要查看result_code来判断

返回信息 return_msg String(128) 签名失败

返回信息,如非空,为错误原因

签名失败

参数格式校验错误

以下字段在return_code为SUCCESS的时候有返回

字段名变量名必填类型示例值描述
小程序ID appid String(32) wx8888888888888888 调用接口提交的小程序ID
商户号 mch_id String(32) 1900000109 调用接口提交的商户号
设备号 device_info String(32) 013467007045764 自定义参数,可以为请求支付的终端设备号等
随机字符串 nonce_str String(32) 5K8264ILTKCH16CQ2502SI8ZNMTM67VS 微信返回的随机字符串
签名 sign String(32) C380BEC2BFD727A4B6845133519F3AD6 微信返回的签名值,详见签名算法
业务结果 result_code String(16) SUCCESS SUCCESS/FAIL
错误代码 err_code String(32) SYSTEMERROR 详细参见下文错误列表
错误代码描述 err_code_des String(128) 系统错误 错误信息描述

以下字段在return_code 和result_code都为SUCCESS的时候有返回

字段名变量名必填类型示例值描述
交易类型 trade_type String(16) JSAPI 交易类型,取值为:JSAPI,NATIVE,APP等,说明详见参数规定
预支付交易会话标识 prepay_id String(64) wx201410272009395522657a690389285100 微信生成的预支付会话标识,用于后续接口调用中使用,该值有效期为2小时
二维码链接 code_url String(64) URl:weixin://wxpay/s/An4baqw trade_type为NATIVE时有返回,用于生成二维码,展示给用户进行扫码支付

举例如下:

<xml>
   <return_code><![CDATA[SUCCESS]]></return_code>
   <return_msg><![CDATA[OK]]></return_msg>
   <appid><![CDATA[wx2421b1c4370ec43b]]></appid>
   <mch_id><![CDATA[10000100]]></mch_id>
   <nonce_str><![CDATA[IITRi8Iabbblz1Jc]]></nonce_str>
   <openid><![CDATA[oUpF8uMuAJO_M2pxb1Q9zNjWeS6o]]></openid>
   <sign><![CDATA[7921E432F65EB8ED0CE9755F0E86D72F]]></sign>
   <result_code><![CDATA[SUCCESS]]></result_code>
   <prepay_id><![CDATA[wx201411101639507cbf6ffd8b0779950874]]></prepay_id>
   <trade_type><![CDATA[JSAPI]]></trade_type>
</xml>

错误码

名称描述原因解决方案
NOAUTH 商户无此接口权限 商户未开通此接口权限 请商户前往申请此接口权限
NOTENOUGH 余额不足 用户帐号余额不足 用户帐号余额不足,请用户充值或更换支付卡后再支付
ORDERPAID 商户订单已支付 商户订单已支付,无需重复操作 商户订单已支付,无需更多操作
ORDERCLOSED 订单已关闭 当前订单已关闭,无法支付 当前订单已关闭,请重新下单
SYSTEMERROR 系统错误 系统超时 系统异常,请用相同参数重新调用
APPID_NOT_EXIST APPID不存在 参数中缺少APPID 请检查APPID是否正确
MCHID_NOT_EXIST MCHID不存在 参数中缺少MCHID 请检查MCHID是否正确
APPID_MCHID_NOT_MATCH appid和mch_id不匹配 appid和mch_id不匹配 请确认appid和mch_id是否匹配
LACK_PARAMS 缺少参数 缺少必要的请求参数 请检查参数是否齐全
OUT_TRADE_NO_USED 商户订单号重复 同一笔交易不能多次提交 请核实商户订单号是否重复提交
SIGNERROR 签名错误 参数签名结果不正确 请检查签名参数和方法是否都符合签名算法要求
XML_FORMAT_ERROR XML格式错误 XML格式错误 请检查XML参数格式是否正确
REQUIRE_POST_METHOD 请使用post方法 未使用post传递参数  请检查请求参数是否通过post方法提交
POST_DATA_EMPTY post数据为空 post数据不能为空 请检查post数据是否为空
NOT_UTF8 编码格式错误 未使用指定编码格式 请使用UTF-8编码格式

 

 https://github.com/f2e-journey/treasure/blob/master/api.md

接口返回的数据结构

返回的响应体类型推荐为 Content-Type: application/json; charset=utf-8, 返回的数据包含在 HTTP 响应体中, 是一个 JSON Object. 该 Object 可能包含 3 个字段 datastatusstatusInfo

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
    "data": {},
    "status": 0,
    "statusInfo": {
        "message": "给用户的提示信息",
        "detail": "用于排查错误的详细错误信息"
    }
}
字段名字段说明
data 业务数据
必须是任意 JSON 数据类型(number/string/boolean/object/array).
推荐始终返回一个 object (即再包一层)以便于扩展字段.
例如: 用户数据应该返回 {"user":{"name":"test"}}, 而不是直接为 {"name":"test"}
status 状态码
必须是 >= 0 的 JSON Number 整数.
  • 0 表示请求处理成功, 此时可以省略 status 字段, 省略时和为 0 时表示同一含义.
  • 非 0 表示发生错误时的错误码, 此时可以省略 data 字段, 并视情况输出 statusInfo 字段作为补充信息
statusInfo 状态信息
必须是任意 JSON 数据类型.
推荐始终返回一个 object 包含 message 和 detail 字段
  • message 字段作为接口处理失败时, 给予用户的友好的提示信息, 即所有给用户的提示信息都统一由后端来处理.
  • detail 字段用来放置接口处理失败时的详细错误信息. 只是为了方便排查错误, 前端无需使用.

例如

  • 接口处理成功时接口返回的数据

    {
        "data": "api result"
        "status": 0
    }
    
  • 接口处理失败时接口返回的数据

    {
        "status": 1,
        "statusInfo": {
            "message": "服务器正忙",
            "detail": {
                "exception": "java.util.List"
            }
        }
    }
    

这样我们就可以非常容易地通过判断 status 来处理数据了

if (!response.status) {
    // status 为 0 或者没有 status 字段时表示接口成功返回了数据
    console.log(response.data);
} else {
    // 失败
    console.error(response.status, response.statusInfo);
    // 统一由服务端返回给用户的提示信息
    alert(response.statusInfo.message);
}

错误码规范: status 字段该如何取值

采用前后端分离开发模式的项目越来越多, 前端负责调用后端的接口来展现界面, 如果有界面显示异常, 需要有快速方便的手段来排查线上错误和定位出职责范围

综合了经验总结和行业实践, 最简单有效的手段是制定出一套统一的错误码规范, 协助多方人员来排查出接口的错误

例如

  • 用户发现错误, 可以截错误码的图, 就能够提供有效的信息帮助开发人员排查错误
  • 测试人员发现错误, 可以通过错误码, 快速定位是前端的问题还是后端接口的问题

因此我们确定提示信息规范为: 当后端接口调用出错时, 接口提供一个用户可以理解的错误提示, 前端展示给用户错误提示和错误码, 给予用户反馈

对于错误码的规范, 参考行业实践, 大致有两种方案

具体实践如下

  • 错误码固定长度, 以区间来划分错误类型(例如 HTTP 的状态码)

    例如: 10404 表示 HTTP 请求 404 错误, 20000 表示 API 调用失败, 30000 代表业务错误, 31000 表示业务A错误, 32000 表示业务B错误

  • 错误码可不固定长度, 以首字母来划分错误类型, 可扩展性更好, 但实际运作还是需要划分区间

    例如: H404 表示 HTTP 请求 404 错误, A100 表示 API 调用失败, B100 表示业务A错误, B200 表示业务B错误

关于错误分类的原则, 我们可以根据发送请求的最终状态来划分

  • 发送失败(即请求根本就没有发送出去)
  • 发送成功
    • HTTP 异常状态(例如 404/500...)
    • HTTP 正常状态(例如 200)
      • 接口调用成功
      • 接口调用失败(业务错误, 即接口规范中 status 非 0 的情况)

最终规范

错误码可不固定长度, 整体格式为: 字母+数字字母作为错误类型, 可扩展性更好, 数字建议划分区间来细分错误

例如:

  • A for API: API 调用失败(请求发送失败)的错误, 例如 A100 表示 URL 非法
  • H for HTTP, HTTP 异常状态的错误, 例如 H404 表示 HTTP 请求404错误
  • B for backend or business, 接口调用失败的错误, 例如 B100 业务A错误, B200 业务B错误
  • C for Client: 客户端错误, 例如 C100 表示解析 JSON 失败
                                                       发送 HTTP 请求
                                                 ┌───────────┴───────────┐
                                              发送成功¹               发送失败²
                                                 │                       │
                                      ┌──────────┴──────────┐            A 例如: A100
                                获得 HTTP 响应       无法获得 HTTP 响应³
                                      │                     │
                                 HTTP status                A 例如: A200
                           ┌──────────┴──────────┐
                       HTTP 成功(200-300)     HTTP 异常
                           │                     |
               {data, status, statusInfo}        H${HTTP status} 例如: H404
               ┌───────────┴───────────┐
          接口调用成功(status:0)   接口调用失败
      ┌────────┴────────┐              |
客户端处理出错      客户端处理正常       B${status}${statusInfo.message} 例如: B100
      |
      C 例如: C100

- 发送成功¹: 服务端收到了 HTTP 请求并返回了 HTTP 响应
- 发送失败²: HTTP 请求没有发送出去(例如由于跨域被浏览器拦截不允许发送), 未到达服务端(即服务端没有收到这个 HTTP 请求)
- 无法获得 HTTP 响应³: 服务端收到了请求并返回了响应, 但客户端由于某些原因无法获得 HTTP 响应, 例如请求的超时处理机制

统一错误提示

  • 错误日志
    • 接口调用出错(${错误码}${HTTP 方法} ${HTTP URL} ${请求参数} ${请求选项} ${请求返回结果}
    • 例如: 接口调用出错(H404) GET https://domain.com {foo: bar} {option1: 'test'} {status: 404}
  • 给用户的提示消息(参考自 QQ 的错误提示消息)
    • 提示消息(错误码: xxx)

      weapp-error-tip weibo-error-tip qq-error-tip

    • 提示消息和错误码之间用换行隔开

    • 错误码整块内容建议弱化使用灰色字

    • 例如

      mobile-error-code-message pc-error-code-message

规范实现: weapp-backend-api

接口实现建议

  • 接口实现的大方向建议遵循 RESTful 风格
  • HTTP 动词: 获取数据用 GET, 新增/修改/发送数据用 POST
    • 例如: 获取用户数据的接口用 GET, 修改用户数据的接口用 POST
  • 对于资源的操作类型, 使用 HTTP 动词来指定, 减少接口 URL 的数量
    • 例如: GET /contact 获取联系人, POST /contact 新增/修改联系人
  • 对外的 ID 字段使用字符串类型
    • 特别核心数据的 ID 字段, 不要使用自增的数字类型, 建议使用无规则的字符串类型(例如UUID), 避免核心数据被轻易抓取
    • 避免使用大数字类型(Long), 因为前端可能承载不了这个精度而溢出得到另外一个数值
    • 例如: Java 中的 Long 类型的数值: 362909601374617692, 作为 JSON 数据返回给前端, 前端拿到的值变成了 362909601374617660
  • 接口字段建议同时给出 ID 字段和用于显示字段, 前端提交数据时只提交 ID 字段
    • 例如: {"sex": 1, "sexText": "男"}
  • 图片的 URL 建议返回完整的 URL
    • 例如: {"pic": "https://domain.com/a.png"}
  • 时间字段建议同时返回时间戳的原始值(或 ISO 标准格式)和用于统一显示的格式化文本
    • 由后端接口集中控制各端的显示, 提供的原始值兼顾前端的自定义显示或者计算(例如倒计时)的需求
    • 避免每个端(例如H5/APP/小程序)都需要对时间做统一的格式化实现, 一旦需要调整, 需要各个端都调整一遍
    • 例如: {"createTime": 1543195480357, "createTimeText": "2018年11月26日"}
  • 统一分页的数据格式
    • 分页请求的参数和分页结果的数据结构

注意

参考

  • E-JSON数据传输标准

  • 有范云协作 让项目的协作姿势更有范儿

    • 交互阶段说明
      • 交互设计师根据产品方的需求对产品进行行为设计和界面设计的阶段,主要产出物为交互设计稿
      • 开发工程师需要做的事情是针对产品需求、交互设计稿中的内容进行技术评审,为产品方、交互设计师提供可行技术实现解决方案,对于多种不同解决方案需针对各种解决方案做分析说明,务必准确传达各种方案的优缺点,并根据需求给出建议方案
    • 系统设计说明
      • 各端开发工程师针对产品需求说明、交互设计稿开始设计系统架构、拆分子系统、划分子系统模块、协调端与端之间的接口规范,这个阶段各端根据实际情况输出若干系统设计说明书等文档
      • 除此之外更重要的是输出端与端之间通信的接口规范,而这个规范则可以借助 NEI 平台 来完成
    • 编码阶段说明
      • 开发工程师根据系统设计阶段的输出,用代码来实现这样的系统,包括技术方案的选型、项目框架的搭建、工具及环境的配置等
      • 其中有些工作可以借助于有范云协作提供的自动化工具 NEI-Toolkit 来完成,比如项目的初始结构代码、在 NEI平台 上定义好的接口规范等
    • 自测阶段说明
      • 各个端的工程师验证自己编写的代码的正确性,按角色不同,测试方式也有所有不同
      • 对于前端和移动端工程师来说,主要是需要测试各种可能的值会不会影响界面展示
      • 对于服务端工程师来说,主要是测试提供给客户端工程师使用的接口的正确性,对于不同的输入参数是否返回了预期的结果
    • 联调阶段说明
      • 主要是连测试环境进行测试
      • 对于前端和移动端工程师来说,主要是需要将本地容器提供的接口换成测试环境的接口
    • 测试阶段说明
      • 开发工程师开发完成后提测的过程,是产品上线前的最后环节
      • 测试工程师会对接 NEI 平台生成接口测试用例代码并集成到自动化测试平台运行,如果NEI平台的接口定义与实际提测的项目不符则此次提测失败,需由开发对照 NEI 平台检查接口实现情况,所以可以保证 NEI 平台上的接口定义始终与线上保持一致
  • 客户端API请求规范

    参数名说明
    imei 国际移动设备身份码
    imsi 客户端用户标识
    t TIMESTAMP,请求的时间戳
    appkey 由服务端颁发的appkey
    sign md5签名串。为了减轻非法恶意请求,每次来自APP的请求都需要对请求参数进行签名以实现安全认证
    lng 手机上获取的经度
    lat 手机上获取的纬度
    ci 渠道标识,格式为:channelId@应用名平台客户端版本,例如:1001@nzaom_android_1.0,其中1001表示应用宝
  • GitHub API | 微博API | 淘宝开放平台 API

  • JSend | JSON API | JSON Schema | JSON-RPC | JWT | OAuth

    TypeDescriptionRequired KeysOptional Keys
    success All went well, and (usually) some data was returned. status, data  
    fail There was a problem with the data submitted, or some pre-condition of the API call wasn't satisfied status, data  
    error An error occurred in processing the request, i.e. an exception was thrown status, message code, data
  • Google JSON Style Guide

  • 最佳实践:更好的设计你的 REST API | RESTful API 设计指南 | Best Practices for Designing a Pragmatic RESTful API | HTTP API Design Guide | The RESTful Cookbook | RESTful API 编写指南

  • Restlet Studio - Web IDE for API design | Swagger | ReDoc | RAML | API Blueprint

 

 

 

 

posted @ 2018-10-26 16:05  papering  阅读(777)  评论(0编辑  收藏  举报