在很多第三方支付渠道都是只采用状态码返回响应, 像是比较常见微信和支付宝方面:
# https://pay.weixin.qq.com/doc/v3/merchant/4012081709
# 微信响应公共错误码, 以 HTTP 响应码做主题
200 - Success - 请求成功
400 - PARAM_ERROR - 参数错误
400 - INVALID_REQUEST - HTTP 请求不符合微信支付 APIv3 接口规则
400 - APPID_MCHID_NOT_MATCH - AppID和mch_id不匹配
400 - INVALID_REQUEST - 无效请求
400 - MCH_NOT_EXISTS - 商户号不存在
401 - SIGN_ERROR - Sign 验证不通过
403 - NO_AUTH - 商户无权限
403 - OUT_TRADE_NO_USED - 商户订单号重复
403 - RULE_LIMIT - 业务规则限制
429 - FREQUENCY_LIMITED - 频率超限
500 - SYSTEM_ERROR - 系统异常,请稍后重试
# https://opendocs.alipay.com/mini/6039ed0c_alipay.trade.create?scene=de4d6a1e0c6e423b9eefa7c3a6dcb7a5&pathHash=779dc517
# 支付宝则是默认都是 200 响应, 由内部的 code|sub_code 去区分异常和业务错误
很早之前我就有疑问为什么不能按照这种方式通过指定 Accept-Language 并在响应结构之中加上 message 做 i18n 做错误返回?
比如按照 curl 模拟提交请求直接就像是:
# 采用 Accept-Language 指定发起环境语言
# 采用 Content-Type 指定发起的数据格式
curl -d '{"referenceOrderId": "2023060801502300000008810000005657"}' \
-H "Accept-Language: ja" \
-H "Content-Type: application/json" \
https://payment.self.com/order/create
这样服务端只需要识别 Accept-Language 直接返回 message="操作に失敗" 即可, 如下所示:
// HTTP 响应码 400
{
message: "操作に失敗",
data: {}
}
还能直接拿到错误消息还能直接拿到, 看起来一切流程都很完美, 但是无形当中也是有很多坑点的.
响应码贫乏
支付架构内部业务响应码是很复杂的, 比如会做大量业务认证, 这种认证可能单接口就有许多不同的响应, 简单罗列下支付宝的业务错误码就有:
- ACQ.ACCESS_FORBIDDEN: 无权限使用接口
- ACQ.BEYOND_PER_RECEIPT_SINGLE_RESTRICTION: 订单金额超过单笔限额
- ACQ.BUYER_ENABLE_STATUS_FORBID: 买家状态非法
- ACQ.BUYER_NOT_EXIST: 买家不存在
- ……
单纯的 400 响应码根本无法囊括这些这么复杂的业务码, 这两家都采用 code|sub_code 方式归类错误提示:
// 微信响应结构
{
"code": "NO_AUTH",
"message": "商户号该产品权限未开通,请前往商户平台>产品中心检查后重试"
}
// 支付宝响应结构
{
"alipay_trade_create_response": {
"code": "20000",
"msg": "Service Currently Unavailable",
"sub_code": "isp.unknow-error",
"sub_msg": "系统繁忙"
},
"sign": "ERITJKEIJKJHKKKKKKKHJEREEEEEEEEEEE"
}
需要说明的就是支付宝的响应结构比起微信更加规范, 提供
sign用于响应参数签名验证确认本次请求的合法性, 商户端严谨可以去验证参数合法性
主要依靠内部的 code|sub_code 暴露给下级商户拦截异常展示自定义提示消息, 单纯的 HTTP 状态实际上只能应对相对简单的业务,
后续必须要处理这种复杂请求状态业务, 这里我把常用错误归类为以下级别:
公共级: 类似参数错误(比如少个必填参数或者参数签名哈希错误) | 商户不存在等从本质上错误的, 直接400|404响应码返回系统级: 这种就是服务级别异常, 比如作为支付商的数据库挂了或者服务器崩溃等情况, 直接返回500做日志记录, 外部不需要知道错误业务级: 类似商户号无法支付(没有开通支付权限) | 商户提交的订单已经存在系统等逻辑不成立的, 需要400响应+扩展业务码
以下就是我自己常用的通用响应格式, 可以参考下在项目日常使用:
// 公共级(200~400响应码), 公共都是以 HTTP.* 方式返回错误, 所以这里直接沿用默认成功返回
// 以 '.' 符号做错误空间划分, status 状态都是采用以大写做标识
{
"status": "HTTP.OK",
"message": "OK",
"data": {
"orderId": "2015042321001004720200028594"
}
}
// 业务级(400~499响应码), 状态字段如果是通用错误, 公共都是以 HTTP.* 方式返回错误
// 比如如果被请求限流的话就是返回 HTTP.TOO_MANY_REQUESTS
{
"status": "HTTP.FORBIDDEN",
"message": "Forbidden",
"data": {}
}
// 如果是内部自定义异常, 就是比如商户不存在的情况, 可以自定义归类错误: MERCHANT.NOT_EXIST
// message 则是沿用 HTTP 响应的错误信息即可
{
"status": "MERCHANT.NOT_EXIST",
"message": "NOT FOUND",
"data": {}
}
// 系统级(500+响应码), 内部系统的异常, 这种异常推荐采用 EXCEPTION.* 方式返回
// 方便识别和其他接口区分开来, 且 message 不要显示任何内部系统错误, 只需要返回 'Internal Server Error'
// 有些异常可能需要被商户捕获的情况, 可以扩展 EXCEPTION.* 命名空间的错误
// 其他未知异常采用 EXCEPTION.UNKNOWN 处理, 也就是通用异常返回
{
"status": "EXCEPTION.SERVER",
"message": "Internal Server Error",
"data": {}
}
本地化麻烦
上面说到, 为什么 message 不采用 header 识别的 Accept-Language 返回对应的语言本地化错误,
这样连错误状态 status 都不需要处理, 直接告诉他们什么错误就行了.
但是这种方式实在是太理想了, 你需要处理以下问题:
- 每次添加某种异常, 都要去处理所有语言翻译版本
- 某些地区遣词造句需要按照当地习俗改动合理
- 有些小语种地区的字体其实因为设备问题是会显示方块无法识别
当然你也可以仅仅支持少数语言, 如果不支持的语言就默认采用 en 之类特定语言处理,
但是这样处理导致在某些地区错误消息根本没办法拿来用.
比如像是韩语如果不支持的话, 突兀弹出的英语错误还不如返回错误状态或者错误码直接由商户那边拦截判断处理; 所以这种本地化翻译只能存在十分理想的状态, 没办法做到真正的全球本地化消息返回.
另外, 别看支付宝返回 {“sub_msg”: “系统繁忙”} 就以为支持本地化, 其实就返回中文和英文两种异常消息, 其他语言都是没支持的
之前做全球化支付的时候就尝试过这种这种消息返回方式, 但是效果很不理想, 常常被反馈 i18n 翻译没跟上, XXX 语言返回又缺失了;
也就是在多次出现问题之后, 才发现直接判处 status 让商户服务端拦截更好, 而不是直接用 message 识别区域语言返回.
很多时候大厂的设计可以学习并且思考为什么会这样做, 大部分都是生产线上掉过坑从而弥补回来的.
结构设计
对于响应结构推荐采用比较简单的 JSON 做基底, 然后通过 Python 等工具才能方便生成通用语言结构体.
{
"HTTP": {
"OK": {
"state": 200,
"message": "OK",
"remark": "通用的请求成功响应"
},
"CREATED": {
"state": 201,
"message": "Created",
"remark": "请求成功且必须要重定向到指定地址情况"
},
"ACCEPTED": {
"state": 202,
"message": "Accepted",
"remark": "服务器已经接收到请求, 后续任务会异步处理"
},
"NO_CONTENT": {
"state": 204,
"message": "No Content",
"remark": "服务器已经接收到请求, 但是不会响应任何内容给客户端"
},
"RESET_CONTENT": {
"state": 205,
"message": "Reset Content",
"remark": "请求成功, 要求客户端可以刷新页面等重置操作"
},
"BAD_REQUEST": {
"state": 400,
"message": "Bad Request",
"remark": "请求参数错误|无效等, 最通用的异常返回"
},
"UNAUTHORIZED": {
"state": 401,
"message": "Unauthorized",
"remark": "身份验证异常, 客户端携带的授权凭证已经失效"
},
"FORBIDDEN": {
"state": 403,
"message": "Forbidden",
"remark": "服务器拒绝该请求, 权限不足的情况会出现"
},
"NOT_FOUND": {
"state": 404,
"message": "Not Found",
"remark": "服务端找不到资源, 检索不到请求所需的实体对象资源"
},
"METHOD_NOT_ALLOWED": {
"state": 405,
"message": "Method Not Allowed",
"remark": "请求方法不允许, 比如有的请求方法只允许 POST 方式做发起请求"
},
"NOT_ACCEPTABLE": {
"state": 406,
"message": "Not Acceptable",
"remark": "服务器无法响应客户端要求的格式, 比如服务器只支持JSON情况要求返回 XML 返回该错误"
},
"REQUEST_TIMEOUT": {
"state": 408,
"message": "Request Timeout",
"remark": "等待请求超时, 可以用于连接第三方服务的时候超时情况"
},
"CONFLICT": {
"state": 409,
"message": "Conflict",
"remark": "发起请求的数据资源已经被修改过, 比如对同个订单同时修改情况必然会有个失败"
},
"PAYLOAD_TOO_LARGE": {
"state": 413,
"message": "Payload Too Large",
"remark": "发起的客户端请求体过大, 服务端无法处理该请求"
},
"UNSUPPORTED_MEDIA_TYPE": {
"state": 415,
"message": "Unsupported Media Type",
"remark": "发起的客户端格式不支持, 比如服务端要求JSON格式但客户端提交XML|FORM等格式"
},
"TOO_MANY_REQUESTS": {
"state": 429,
"message": "Too Many Requests",
"remark": "客户端请求过于频繁, 请求限流处理"
}
},
"EXCEPTION": {
"INTERNAL_SERVER_ERROR": {
"state": 500,
"message": "Internal Server Error",
"remark": "通用服务器抛出的异常, 具体错误需要服务端定位"
},
"BAD_GATEWAY": {
"state": 502,
"message": "Bad Gateway",
"remark": "服务器作为网关时, 收到上游服务器的无效响应"
},
"GATEWAY_TIMEOUT": {
"state": 504,
"message": "Gateway Timeout",
"remark": "服务器作为网关时, 等待上游服务器响应超时"
}
},
"PARAMETER": {
"PARTNER_ERROR": {
"state": 400,
"message": "Bad Request",
"remark": "商户相关参数异常"
},
"SIGN_ERROR": {
"state": 401,
"message": "Unauthorized",
"remark": "SIGN验证异常"
},
"PARTNER_INVALID": {
"state": 400,
"message": "Bad Request",
"remark": "参数无效, 用于在二次验证处理再处理时候失败返回"
}
},
"MERCHANT": {
"NOT_EXISTS": {
"state": 404,
"message": "Not Found",
"remark": "商户号不存在"
},
"NOT_UNAUTHORIZED": {
"state": 401,
"message": "Unauthorized",
"remark": "商户号无权限"
}
},
"ORDER": {
"TRADE_NO_USED": {
"state": 400,
"message": "Bad Request",
"remark": "商户订单重复"
},
"TRADE_HAS_CLOSE": {
"state": 400,
"message": "Bad Request",
"remark": "商户订单关闭"
},
"TRADE_HAS_SUCCESS": {
"state": 400,
"message": "Bad Request",
"remark": "商户订单已完成"
}
}
}
这个 JSON 就是统一的响应清单文件, 之后就是手动将 JSON 文件转化成其他语言的 类|枚举|函数 文件格式.
对于这种配置项目必须
文档化, 这样方便后续多个系统做统筹翻译到其他编程语言处理.
这里采用 Python 将响应文档转化成以下模板文件:
- Markdown: 文档
- Java: Java 语言枚举
- PHP: PHP 语言静态属性
转换脚本文件内容下:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Module: 响应文档转化成为对应语言模板
Author: MeteorCat
"""
import json
import sys
import os
def json_to_markdown_file(json_data, class_name="ResponseCode"):
"""
将JSON数据转换为Markdown文档
参数:
json_data: 输入的JSON数据
class_name: 生成的Markdown文档名
返回:
生成的Markdown文档字符串
"""
# 构建 Markdown文档
markdown_code = f"# Document:{class_name} {{\n\n"
markdown_code += "|HTTP响应状态码|响应消息内容|逻辑响应状态|备注说明|\n"
markdown_code += "| ---------- | -------- | ------- | -----|\n"
# 用于记录所有枚举项,确保不重复
enum_items = []
# 遍历JSON中的每个分类
for category, items in json_data.items():
# 遍历每个状态码项
for item_name, properties in items.items():
# 追加枚举内容
reason = f"{category}.{item_name}"
item_name = f"{category}_{item_name}"
# 检查是否已存在同名枚举项
if item_name in enum_items:
print(f"警告: 枚举项 {item_name} 重复出现,已跳过重复项")
continue
enum_items.append(item_name)
state = properties["state"]
message = properties["message"].replace('"', '\\"') # 转义双引号
remark = properties["remark"] # 注释
# 添加内容
markdown_code += f"|{state}|{message}|{reason}|{remark}|\n"
return markdown_code
def json_to_java_enum(json_data, class_name="ResponseCode"):
"""
将JSON数据转换为Java枚举类代码
参数:
json_data: 输入的JSON数据
class_name: 生成的Java类名
返回:
生成的Java代码字符串
"""
# 构建Java代码
java_code = f"public enum {class_name} {{\n"
# 用于记录所有枚举项,确保不重复
enum_items = []
# 遍历JSON中的每个分类
for category, items in json_data.items():
# 遍历每个状态码项
for item_name, properties in items.items():
# 追加枚举内容
reason = f"{category}.{item_name}"
item_name = f"{category}_{item_name}"
# 检查是否已存在同名枚举项
if item_name in enum_items:
print(f"警告: 枚举项 {item_name} 重复出现,已跳过重复项")
continue
enum_items.append(item_name)
state = properties["state"]
message = properties["message"].replace('"', '\\"') # 转义双引号
remark = properties["remark"] # 注释
# 添加注释
java_code += "\t/**\n"
java_code += f"\t* {remark} \n"
java_code += "\t*/\n"
# 添加内容
java_code += f"\t{item_name}({state}, \"{reason}\" , \"{message}\"),\n"
# 移除最后一个逗号
if enum_items:
java_code = java_code.rstrip(",\n") + ";\n\n"
else:
java_code += "\n"
# 添加枚举属性和方法
java_code += """\tprivate final int httpStatus;
\tprivate final String reasonStatus;
\tprivate final String message;
\t%s(int httpStatus,String reasonStatus, String message) {
\t\tthis.httpStatus = httpStatus;
\t\tthis.reasonStatus = reasonStatus;
\t\tthis.message = message;
\t}
\tpublic int getHttpStatus() {
\t\treturn httpStatus;
\t}
\tpublic String getReasonStatus() {
\t\treturn reasonStatus;
\t}
\tpublic String getMessage() {
\t\treturn message;
\t}
}""" % class_name
return java_code
def json_to_php_clazz(json_data, class_name="ResponseCode"):
"""
将JSON数据转换为PHP类代码
参数:
json_data: 输入的JSON数据
class_name: 生成的PHP类名
返回:
生成的PHP代码字符串
"""
# 构建PHP代码
php_code = f"<?php\nclass {class_name} {{\n"
# 用于记录所有枚举项,确保不重复
enum_items = []
# 遍历JSON中的每个分类
for category, items in json_data.items():
# 遍历每个状态码项
for item_name, properties in items.items():
# 追加枚举内容
reason = f"{category}.{item_name}"
item_name = f"{category}_{item_name}"
# 检查是否已存在同名枚举项
if item_name in enum_items:
print(f"警告: 枚举项 {item_name} 重复出现,已跳过重复项")
continue
enum_items.append(item_name)
state = properties["state"]
message = properties["message"].replace('"', '\\"') # 转义双引号
remark = properties["remark"] # 注释
# 添加注释
php_code += "\t/**\n"
php_code += f"\t* {remark} \n"
php_code += "\t*/\n"
# 添加内容
php_code += f"\tpublic static array ${item_name} = array({state}, \"{reason}\" , \"{message}\");\n"
php_code += "}"
return php_code
if __name__ == "__main__":
# 检查是否提供了文件路径参数
if len(sys.argv) != 2:
print("Usage: python response.py <input_filename> <output_filename>")
sys.exit(1)
input_filename = sys.argv[1]
output_filename = 'ResponseCode'
# 确认文件存在
if not os.path.exists(input_filename):
print(f"error: input file '{input_filename}' not found")
sys.exit(1)
# 尝试解析文件内容验证是否为有效的JSON
try:
with open(input_filename, 'r', encoding='utf-8') as fr:
json_input = json.load(fr)
# 转化为 Markdown 文档
markdown_file = f"{output_filename}.md"
markdown_code = json_to_markdown_file(json_input)
with open(markdown_file, "w", encoding="utf-8") as fw:
fw.write(markdown_code)
print(f"Save '{markdown_file}' File Succeeded")
# 转换为Java枚举文件
java_enum_file = f"{output_filename}.java"
java_enum_code = json_to_java_enum(json_input)
with open(java_enum_file, "w", encoding="utf-8") as fw:
fw.write(java_enum_code)
print(f"Save '{java_enum_file}' File Succeeded")
# 转化为 PHP 静态类
php_enum_file = f"{output_filename}.php"
php_enum_code = json_to_php_clazz(json_input)
with open(php_enum_file, "w", encoding="utf-8") as fw:
fw.write(php_enum_code)
print(f"Save '{php_enum_file}' File Succeeded")
except json.JSONDecodeError as e:
print(f"error: file '{input_filename}' converted")
sys.exit(1)
except Exception as e:
print(f"error: {str(e)}")
sys.exit(1)
最后生成的通用翻译模板文件修改下直接发给对应负责程序就行了,
Java 文件直接采用通用枚举返回即可.
public enum ResponseCode {
/**
* 通用的请求成功响应
*/
HTTP_OK(200, "HTTP.OK", "OK"),
/**
* 请求成功且必须要重定向到指定地址情况
*/
HTTP_CREATED(201, "HTTP.CREATED", "Created"),
/**
* 服务器已经接收到请求, 后续任务会异步处理
*/
HTTP_ACCEPTED(202, "HTTP.ACCEPTED", "Accepted"),
/**
* 服务器已经接收到请求, 但是不会响应任何内容给客户端
*/
HTTP_NO_CONTENT(204, "HTTP.NO_CONTENT", "No Content"),
/**
* 请求成功, 要求客户端可以刷新页面等重置操作
*/
HTTP_RESET_CONTENT(205, "HTTP.RESET_CONTENT", "Reset Content"),
/**
* 请求参数错误|无效等, 最通用的异常返回
*/
HTTP_BAD_REQUEST(400, "HTTP.BAD_REQUEST", "Bad Request"),
/**
* 身份验证异常, 客户端携带的授权凭证已经失效
*/
HTTP_UNAUTHORIZED(401, "HTTP.UNAUTHORIZED", "Unauthorized"),
/**
* 服务器拒绝该请求, 权限不足的情况会出现
*/
HTTP_FORBIDDEN(403, "HTTP.FORBIDDEN", "Forbidden"),
/**
* 服务端找不到资源, 检索不到请求所需的实体对象资源
*/
HTTP_NOT_FOUND(404, "HTTP.NOT_FOUND", "Not Found"),
/**
* 请求方法不允许, 比如有的请求方法只允许 POST 方式做发起请求
*/
HTTP_METHOD_NOT_ALLOWED(405, "HTTP.METHOD_NOT_ALLOWED", "Method Not Allowed"),
/**
* 服务器无法响应客户端要求的格式, 比如服务器只支持JSON情况要求返回 XML 返回该错误
*/
HTTP_NOT_ACCEPTABLE(406, "HTTP.NOT_ACCEPTABLE", "Not Acceptable"),
/**
* 等待请求超时, 可以用于连接第三方服务的时候超时情况
*/
HTTP_REQUEST_TIMEOUT(408, "HTTP.REQUEST_TIMEOUT", "Request Timeout"),
/**
* 发起请求的数据资源已经被修改过, 比如对同个订单同时修改情况必然会有个失败
*/
HTTP_CONFLICT(409, "HTTP.CONFLICT", "Conflict"),
/**
* 发起的客户端请求体过大, 服务端无法处理该请求
*/
HTTP_PAYLOAD_TOO_LARGE(413, "HTTP.PAYLOAD_TOO_LARGE", "Payload Too Large"),
/**
* 发起的客户端格式不支持, 比如服务端要求JSON格式但客户端提交XML|FORM等格式
*/
HTTP_UNSUPPORTED_MEDIA_TYPE(415, "HTTP.UNSUPPORTED_MEDIA_TYPE", "Unsupported Media Type"),
/**
* 客户端请求过于频繁, 请求限流处理
*/
HTTP_TOO_MANY_REQUESTS(429, "HTTP.TOO_MANY_REQUESTS", "Too Many Requests"),
/**
* 通用服务器抛出的异常, 具体错误需要服务端定位
*/
EXCEPTION_INTERNAL_SERVER_ERROR(500, "EXCEPTION.INTERNAL_SERVER_ERROR", "Internal Server Error"),
/**
* 服务器作为网关时, 收到上游服务器的无效响应
*/
EXCEPTION_BAD_GATEWAY(502, "EXCEPTION.BAD_GATEWAY", "Bad Gateway"),
/**
* 服务器作为网关时, 等待上游服务器响应超时
*/
EXCEPTION_GATEWAY_TIMEOUT(504, "EXCEPTION.GATEWAY_TIMEOUT", "Gateway Timeout"),
/**
* 商户相关参数异常
*/
PARAMETER_PARTNER_ERROR(400, "PARAMETER.PARTNER_ERROR", "Bad Request"),
/**
* SIGN验证异常
*/
PARAMETER_SIGN_ERROR(401, "PARAMETER.SIGN_ERROR", "Unauthorized"),
/**
* 参数无效, 用于在二次验证处理再处理时候失败返回
*/
PARAMETER_PARTNER_INVALID(400, "PARAMETER.PARTNER_INVALID", "Bad Request"),
/**
* 商户号不存在
*/
MERCHANT_NOT_EXISTS(404, "MERCHANT.NOT_EXISTS", "Not Found"),
/**
* 商户号无权限
*/
MERCHANT_NOT_UNAUTHORIZED(401, "MERCHANT.NOT_UNAUTHORIZED", "Unauthorized"),
/**
* 商户订单重复
*/
ORDER_TRADE_NO_USED(400, "ORDER.TRADE_NO_USED", "Bad Request"),
/**
* 商户订单关闭
*/
ORDER_TRADE_HAS_CLOSE(400, "ORDER.TRADE_HAS_CLOSE", "Bad Request"),
/**
* 商户订单已完成
*/
ORDER_TRADE_HAS_SUCCESS(400, "ORDER.TRADE_HAS_SUCCESS", "Bad Request");
private final int httpStatus;
private final String reasonStatus;
private final String message;
ResponseCode(int httpStatus, String reasonStatus, String message) {
this.httpStatus = httpStatus;
this.reasonStatus = reasonStatus;
this.message = message;
}
public int getHttpStatus() {
return httpStatus;
}
public String getReasonStatus() {
return reasonStatus;
}
public String getMessage() {
return message;
}
}
PHP版本高版本才有枚举特性, 为了保持兼容性一般都是采用静态类处理:
<?php
class ResponseCode {
/**
* 通用的请求成功响应
*/
public static array $HTTP_OK = array(200, "HTTP.OK" , "OK");
/**
* 请求成功且必须要重定向到指定地址情况
*/
public static array $HTTP_CREATED = array(201, "HTTP.CREATED" , "Created");
/**
* 服务器已经接收到请求, 后续任务会异步处理
*/
public static array $HTTP_ACCEPTED = array(202, "HTTP.ACCEPTED" , "Accepted");
/**
* 服务器已经接收到请求, 但是不会响应任何内容给客户端
*/
public static array $HTTP_NO_CONTENT = array(204, "HTTP.NO_CONTENT" , "No Content");
/**
* 请求成功, 要求客户端可以刷新页面等重置操作
*/
public static array $HTTP_RESET_CONTENT = array(205, "HTTP.RESET_CONTENT" , "Reset Content");
/**
* 请求参数错误|无效等, 最通用的异常返回
*/
public static array $HTTP_BAD_REQUEST = array(400, "HTTP.BAD_REQUEST" , "Bad Request");
/**
* 身份验证异常, 客户端携带的授权凭证已经失效
*/
public static array $HTTP_UNAUTHORIZED = array(401, "HTTP.UNAUTHORIZED" , "Unauthorized");
/**
* 服务器拒绝该请求, 权限不足的情况会出现
*/
public static array $HTTP_FORBIDDEN = array(403, "HTTP.FORBIDDEN" , "Forbidden");
/**
* 服务端找不到资源, 检索不到请求所需的实体对象资源
*/
public static array $HTTP_NOT_FOUND = array(404, "HTTP.NOT_FOUND" , "Not Found");
/**
* 请求方法不允许, 比如有的请求方法只允许 POST 方式做发起请求
*/
public static array $HTTP_METHOD_NOT_ALLOWED = array(405, "HTTP.METHOD_NOT_ALLOWED" , "Method Not Allowed");
/**
* 服务器无法响应客户端要求的格式, 比如服务器只支持JSON情况要求返回 XML 返回该错误
*/
public static array $HTTP_NOT_ACCEPTABLE = array(406, "HTTP.NOT_ACCEPTABLE" , "Not Acceptable");
/**
* 等待请求超时, 可以用于连接第三方服务的时候超时情况
*/
public static array $HTTP_REQUEST_TIMEOUT = array(408, "HTTP.REQUEST_TIMEOUT" , "Request Timeout");
/**
* 发起请求的数据资源已经被修改过, 比如对同个订单同时修改情况必然会有个失败
*/
public static array $HTTP_CONFLICT = array(409, "HTTP.CONFLICT" , "Conflict");
/**
* 发起的客户端请求体过大, 服务端无法处理该请求
*/
public static array $HTTP_PAYLOAD_TOO_LARGE = array(413, "HTTP.PAYLOAD_TOO_LARGE" , "Payload Too Large");
/**
* 发起的客户端格式不支持, 比如服务端要求JSON格式但客户端提交XML|FORM等格式
*/
public static array $HTTP_UNSUPPORTED_MEDIA_TYPE = array(415, "HTTP.UNSUPPORTED_MEDIA_TYPE" , "Unsupported Media Type");
/**
* 客户端请求过于频繁, 请求限流处理
*/
public static array $HTTP_TOO_MANY_REQUESTS = array(429, "HTTP.TOO_MANY_REQUESTS" , "Too Many Requests");
/**
* 通用服务器抛出的异常, 具体错误需要服务端定位
*/
public static array $EXCEPTION_INTERNAL_SERVER_ERROR = array(500, "EXCEPTION.INTERNAL_SERVER_ERROR" , "Internal Server Error");
/**
* 服务器作为网关时, 收到上游服务器的无效响应
*/
public static array $EXCEPTION_BAD_GATEWAY = array(502, "EXCEPTION.BAD_GATEWAY" , "Bad Gateway");
/**
* 服务器作为网关时, 等待上游服务器响应超时
*/
public static array $EXCEPTION_GATEWAY_TIMEOUT = array(504, "EXCEPTION.GATEWAY_TIMEOUT" , "Gateway Timeout");
/**
* 商户相关参数异常
*/
public static array $PARAMETER_PARTNER_ERROR = array(400, "PARAMETER.PARTNER_ERROR" , "Bad Request");
/**
* SIGN验证异常
*/
public static array $PARAMETER_SIGN_ERROR = array(401, "PARAMETER.SIGN_ERROR" , "Unauthorized");
/**
* 参数无效, 用于在二次验证处理再处理时候失败返回
*/
public static array $PARAMETER_PARTNER_INVALID = array(400, "PARAMETER.PARTNER_INVALID" , "Bad Request");
/**
* 商户号不存在
*/
public static array $MERCHANT_NOT_EXISTS = array(404, "MERCHANT.NOT_EXISTS" , "Not Found");
/**
* 商户号无权限
*/
public static array $MERCHANT_NOT_UNAUTHORIZED = array(401, "MERCHANT.NOT_UNAUTHORIZED" , "Unauthorized");
/**
* 商户订单重复
*/
public static array $ORDER_TRADE_NO_USED = array(400, "ORDER.TRADE_NO_USED" , "Bad Request");
/**
* 商户订单关闭
*/
public static array $ORDER_TRADE_HAS_CLOSE = array(400, "ORDER.TRADE_HAS_CLOSE" , "Bad Request");
/**
* 商户订单已完成
*/
public static array $ORDER_TRADE_HAS_SUCCESS = array(400, "ORDER.TRADE_HAS_SUCCESS" , "Bad Request");
}
注: 不要把功能和第三方那些响应工具类结合在一起, 如果更换项目依赖的时候会带来很大麻烦