HTTP请求规范
HTTP调用方式说明
本开放接口,针对合作接入方,以REST风格的HTTP服务接口方式,或模块界面集成方式,提供各种税务、财务、业务的相关能力服务。
客户系统可以根据自己系统的情况,选择不同的实现语言来实现对接。本文档以java为主要示例语言。
接口请求调用
1、Java语言推荐使用SDK来进行开发
2、其他语言可以面向http接口进行开发
说明如下:
1)请求方法
所有请求都使用POST方法来请求
2)获取access_token
如何获取access_token请参考获取Access_token
3)请求参数0
- 公共请求头
除了HTTP协议中规定的头信息以外,本开放接口额外做以下头信息要求:
参数名称 | 参数类型 | 说明 |
---|---|---|
Content-Type | String | 请填写application/json |
access_token | String | 大多数接口,需要通过验证身份以后才能访问,需要携带该头信息;请从OAuth接口获取的access_token |
req_date | Long | 当前时间戳的毫秒数。可以参考java的System.currentTimeMillis()方法生成;(如果未携带该头信息,或与服务端的时间差超过 15 分钟,则云端拒绝该请求) |
req_sign | String | 签名校验请求的合法性。签名算法参考 |
- 公共返回报文
在所有请求的返回值里,有一些公共的字段:
参数名称 | 参数类型 | 说明 |
---|---|---|
success | Boolean | 接口是否成功(是否发生业务异常) |
req_id | String | 由服务器端生成的唯一标识,对应每次请求。排查接口异常时,可提供该字段方便定位 |
timestamp | Long | 接口返回时的时间戳 |
time | Long | 本次请求花费的时间 |
- 返回结果
请求成功时返回结果示例:
{
"result": {
"success": true,
"req_id": "e2ef26f2867a41d4962e3e59c3f8eaa8",
"timestamp": 1581581634397,
"time": 2516
},
"value": {
}
}
请求异常时返回示例
{
"result": {
"success": false,
"req_id": "a5318b0f684b40b5941fa89aa549f60e",
"time": 0,
"timestamp": 1581582849905
},
"error": {
"code": "40100",
"message": "未登录!"
}
}
说明:
4)签名机制
获取access_token
1、获取AppKey和AppSecret
请联系接口提供商,获取AppKey和AppSecret
2、调用接口获取access_token
可通过调用OAuth系列接口来获取access_token
请求地址
POST /v1/AGG/oauth2/login HTTP/1.1
Header头信息
Content-Type : application/json;charset=UTF-8
- Body参数
Request Body 为 JSON 格式,说明如下。
参数名称 | 参数类型 | 说明 |
---|---|---|
grant_type | String | 固定client_credentials |
client_appkey | Long | 第一步获取的AppKey |
client_secret | String | 第一步获取的appsecret的md5值(应为32位小写) |
示例参数
{
"grant_type":"client_credentials",
"client_appkey":"xxxxxx",
"client_secret":"xxxxxxxxxxxxxxxxxxxx"
}
- 返回值
返回的结果为JSON格式,遵循公共报文格式,示例如下:
示例返回结果:
{
"result": {
"success": true,
"req_id": "eca0149cd41e42e2a15e74411a90e59a",
"timestamp": 1581586845961,
"time": 196
},
"value": {
"access_token": "eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJbLTEsLTEsLTEsMTAwLFwiXCIsMTAwMDEwMDEsbnVsbCxcIlwiLC0xXSIsImV4cCI6MTU4Mjg4Mjg0NSwiaWF0IjoxNTgxNTg2ODQ1fQ.T4GTFFzf6xD2n1rrCFVu88dQA8ipEobX2_i-Ub7qvIkxrTScmUm_113r1VEsTGhysA-jLFVwFWOtRqEaWvIvVA",
"expires_in": 1296000000,
"refresh_token": "eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJbLTEsLTEsLTEsMTAwLFwiXCIsMTAwMDEwMDEsbnVsbCxcIlwiLC0xXSIsImV4cCI6MTU4NDE3ODg0NSwiaWF0IjoxNTgxNTg2ODQ1fQ.CeW-bvz5Rmv75uTUwY84dODneN23JApNI3h6I-CnmXPzRCfe8MgVWXs3CSqL6ZQefchKcRdCwNghu8KYGRa3hQ"
}
}
3、刷新access_token
获取access_token时,expires_in字段返回过期时间(单位毫秒),在这个时间之后access_token将会失效。 在失效前,请重新登录或调用刷新接口,获取新的access_token
签名方法
报文签名
每个请求头都需要添加req_sign字段,来验证请求的合法性,填写方法如下:
1、req_sign头信息填写的内容如下:
req_sign: API-SV1:<AppKey>:<Signature>
其中:
- API-SV1:表示签名算法版本,暂时固定API-SV1
- AppKey:为分配给接入方的AppKey
- Signature:为签名值,计算方法见下面描述
2、签名值的计算方法:
第一步,拼装待签名字符串
待签名字符串 = HTTPMethod + "_" + Content-Md5 + "_" + req_date + "_" + access_token + "_" + AppSecret
其中:
- HTTPMethod:为请求的方法,通常为POST
- Content-Md5:为请求Body内容的md5 注意,本文档中 md5 相关的结果都转为小写处理
- req_date:为请求头信息中的req_date
- access_token:为AppKey和AppSecret登录后获取,获取方法参考:获取Access_token
- AppSecret:为分配给接入方的密钥
注意:签名字符串必须为UTF-8格式,含有中文字符的签名串必须先进行UTF-8编码。
第二步,计算签名
签名值 = Base64(MD5(待签名字符串)))
3、 签名示例:
请求url如下:
http://localhost:8086/v1/GS/Api/QYJBXX
请求报文如下时:
{"nsrsbh":"915211111111111111"}
签名计算方法如下:
待签名字符串 = POST_4e7f9b81e299ad014cfbc6949c3f4e04_1581588537349_实际获取的accesstoken_实际密码
签名结果:API-SV1:10001001:ZDkwNmJlMzg2NzEyZThlZWEyMDBjODViYTk4ZDQwNzE=
接口调用
HTTP调用
通过postman工具调用。
1、参数
变量文件:local.postman_environment.json
{
"id": "82e8d614-f519-491b-a7a0-8c5a7e3ea24f",
"name": "local",
"values": [
{
"key": "taxurl",
"value": "http://test-agg-api.qixiangyun.com",
"enabled": true,
"type": "text"
},
{
"key": "client_appkey",
"value": "", //获取的AppKey
"enabled": true,
"type": "text"
},
{
"key": "client_secret",
"value": "", //获取的appsecret的md5值(应为32位小写)
"enabled": true,
"type": "text"
},
{
"key": "AppSecret",
"value": "", //获取的appsecret
"enabled": true,
"type": "text"
},
{
"key": "access_token",
"value": "",
"enabled": true,
"type": "text"
},
{
"key": "aggOrgId",
"value": 0,
"enabled": true,
"type": "text"
}
],
"_postman_variable_scope": "environment",
"_postman_exported_at": "2021-01-26T08:11:13.711Z",
"_postman_exported_using": "Postman/6.0.10"
}
2、示例
示例文件:Tax.postman_collection.json
{
"id": "2e7d1c3c-1cae-4bb3-8387-ef4a9fa0975c",
"name": "Tax",
"description": null,
"auth": null,
"events": null,
"variables": [
{
"id": "e29c98d2-d212-4eaf-9a7a-82f46253400b",
"key": "baseUrl",
"value": "http://petstore.swagger.io/v1",
"type": "string"
}
],
"order": [
"d78af170-fb97-47ac-a5ee-99ee6fddf741",
"9e64d923-4f6a-471b-a2a9-4f71b1477c74",
"872f42ce-d7ff-461a-a453-93abeb5c3434",
"ea5c3f97-156b-409f-9414-717743a89d7d",
"7244f0fc-af4e-4f2e-a1dd-326cce8bb9fc"
],
"folders_order": [],
"folders": [],
"requests": [
{
"id": "7244f0fc-af4e-4f2e-a1dd-326cce8bb9fc",
"name": "writeValueAddedTaxData",
"url": "{{taxurl}}/AGG/taxReport/writeValueAddedTaxData",
"description": null,
"data": [],
"dataMode": "raw",
"headerData": [
{
"key": "access_token",
"type": "text",
"value": "{{access_token}}"
},
{
"key": "req_date",
"type": "text",
"value": "{{req_date}}"
},
{
"key": "req_sign",
"type": "text",
"value": "{{req_sign}}"
},
{
"key": "Content-Length",
"type": "text",
"value": "application/json;charset=UTF-8",
"enabled": false
}
],
"method": "POST",
"pathVariableData": [],
"queryParams": [],
"auth": null,
"events": [
{
"listen": "prerequest",
"script": {
"exec": [
"pm.globals.set(\"req_date\",Math.round(new Date().getTime()) );\r",
"\r",
"//req_sign: API-SV1:<AppKey>:<Signature>\r",
"//req_sign \r",
"//签名值 = Base64(MD5(待签名字符串)))\r",
"//待签名字符串 = POST + \"_\" + Content-Md5 + \"_\" + req_date + \"_\" + access_token + \"_\" + AppSecret\r",
"var Content_Md5= CryptoJS.MD5(CryptoJS.enc.Utf8.parse(request.data)).toString();\r",
"var freq_sign = \"POST\" + \"_\" + Content_Md5 + \"_\" + pm.globals.get('req_date') + \"_\" +pm.environment.get(\"access_token\")+ \"_\" +pm.environment.get(\"AppSecret\");\r",
"var freq_signMD5= CryptoJS.MD5(freq_sign).toString();\r",
"\r",
"var freq_signBase64=CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(freq_signMD5));\r",
"\r",
"var Signature=freq_signBase64;\r",
"var req_sign=\"API-SV1:\"+pm.environment.get(\"client_appkey\")+\":\"+Signature;\r",
"pm.globals.set(\"req_sign\", req_sign);\r",
"\r",
"\r",
"var access_tokenTest= pm.environment.get(\"access_token\");\r",
"pm.globals.set(\"access_tokenTest\", access_tokenTest);\r",
"\r",
"pm.globals.set(\"freq_signMD5\", freq_signMD5);\r",
"pm.globals.set(\"request.data\", request.data);\r",
"pm.globals.set(\"client_appkey\", pm.environment.get(\"client_appkey\"));\r",
"pm.globals.set(\"access_token\", pm.environment.get(\"access_token\"));\r",
"pm.globals.set(\"req_sign\", req_sign);\r",
"\r",
"\r",
"\r",
" \r",
" "
],
"type": "text/javascript"
}
}
],
"folder": null,
"rawModeData": "{\r\n \"period\":1,\r\n \"year\":2021,\r\n \"aggOrgId\":{{aggOrgId}},\r\n \"ybData\":\"ybData字符串\"\r\n}\r\n",
"headers": "access_token: {{access_token}}\nreq_date: {{req_date}}\nreq_sign: {{req_sign}}\n//Content-Length: application/json;charset=UTF-8\n",
"pathVariables": {}
},
{
"id": "872f42ce-d7ff-461a-a453-93abeb5c3434",
"name": "getWebUrl",
"url": "{{taxurl}}/AGG/getWebUrl",
"description": null,
"data": [],
"dataMode": "raw",
"headerData": [
{
"key": "access_token",
"value": "{{access_token}}"
},
{
"key": "req_date",
"value": "{{req_date}}"
},
{
"key": "req_sign",
"value": "{{req_sign}}"
},
{
"key": "Content-Length",
"value": "application/json;charset=UTF-8",
"enabled": false
},
{
"key": "Content-Type",
"value": "application/json"
}
],
"method": "POST",
"pathVariableData": [],
"queryParams": [],
"auth": null,
"events": [
{
"listen": "prerequest",
"script": {
"exec": [
"pm.globals.set(\"req_date\",Math.round(new Date().getTime()) );\r",
"\r",
"//req_sign: API-SV1:<AppKey>:<Signature>\r",
"//req_sign \r",
"//签名值 = Base64(MD5(待签名字符串)))\r",
"//待签名字符串 = POST + \"_\" + Content-Md5 + \"_\" + req_date + \"_\" + access_token + \"_\" + AppSecret\r",
"var Content_Md5= CryptoJS.MD5(CryptoJS.enc.Utf8.parse(request.data)).toString();\r",
"var freq_sign = \"POST\" + \"_\" + Content_Md5 + \"_\" + pm.globals.get('req_date') + \"_\" +pm.environment.get(\"access_token\")+ \"_\" +pm.environment.get(\"AppSecret\");\r",
"var freq_signMD5= CryptoJS.MD5(freq_sign).toString();\r",
"\r",
"var freq_signBase64=CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(freq_signMD5));\r",
"\r",
"var Signature=freq_signBase64;\r",
"var req_sign=\"API-SV1:\"+pm.environment.get(\"client_appkey\")+\":\"+Signature;\r",
"pm.globals.set(\"req_sign\", req_sign);\r",
"\r",
"console.log(\"test getWebUrl access_token : \"+pm.environment.get(\"access_token\"))\r",
"\r",
"\r",
" \r",
" "
],
"type": "text/javascript"
}
}
],
"folder": null,
"rawModeData": "{\"nsrsbh\":\"91110111MA01J4B53E\",\"aggOrgId\":\"316548711211200\",\"pageName\":\"edfx-app-org\"}",
"headers": "access_token: {{access_token}}\nreq_date: {{req_date}}\nreq_sign: {{req_sign}}\n//Content-Length: application/json;charset=UTF-8\nContent-Type: application/json\n",
"pathVariables": {}
},
{
"id": "9e64d923-4f6a-471b-a2a9-4f71b1477c74",
"name": "create",
"url": "{{taxurl}}/AGG/org/create",
"description": null,
"data": [],
"dataMode": "raw",
"headerData": [
{
"key": "access_token",
"value": "{{access_token}}"
},
{
"key": "req_date",
"value": "{{req_date}}"
},
{
"key": "req_sign",
"value": "{{req_sign}}"
},
{
"key": "Content-Length",
"value": "application/json;charset=UTF-8",
"enabled": false
},
{
"key": "Content-Type",
"value": "application/json"
}
],
"method": "POST",
"pathVariableData": [],
"queryParams": [],
"auth": null,
"events": [
{
"listen": "prerequest",
"script": {
"exec": [
"pm.globals.set(\"req_date\",Math.round(new Date().getTime()) );\r",
"\r",
"//req_sign: API-SV1:<AppKey>:<Signature>\r",
"//req_sign \r",
"//签名值 = Base64(MD5(待签名字符串)))\r",
"//待签名字符串 = POST + \"_\" + Content-Md5 + \"_\" + req_date + \"_\" + access_token + \"_\" + AppSecret\r",
"var Content_Md5= CryptoJS.MD5(CryptoJS.enc.Utf8.parse(request.data)).toString();\r",
"var freq_sign = \"POST\" + \"_\" + Content_Md5 + \"_\" + pm.globals.get('req_date') + \"_\" +pm.environment.get(\"access_token\")+ \"_\" +pm.environment.get(\"AppSecret\");\r",
"var freq_signMD5= CryptoJS.MD5(freq_sign).toString();\r",
"\r",
"var freq_signBase64=CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(freq_signMD5));\r",
"\r",
"var Signature=freq_signBase64;\r",
"var req_sign=\"API-SV1:\"+pm.environment.get(\"client_appkey\")+\":\"+Signature;\r",
"pm.globals.set(\"req_sign\", req_sign);\r",
"\r",
"\r",
"console.log(\"test create access_token : \"+pm.environment.get(\"access_token\"))\r",
"\r",
"\r",
"\r",
" \r",
" "
],
"type": "text/javascript"
}
},
{
"listen": "test",
"script": {
"exec": [
"// 把responseBody转为json字符串\r",
"var data = JSON.parse(responseBody);\r",
"// 设置环境变量token,供后面的接口引用,位置就是上一步获取的位置\r",
"pm.environment.set(\"aggOrgId\", data.value.aggOrgId);\r",
"\r",
"console.log(\"test aggOrgId : \"+data.value.aggOrgId)\r",
""
],
"type": "text/javascript"
}
}
],
"folder": null,
"rawModeData": "{\"nsrsbh\":\"91110111MA01J4B53E\",\"aggOrgName\":\"北京XX管理有限公司\",\"orgTaxLogin\":{\"dq\":\"11\"}}",
"headers": "access_token: {{access_token}}\nreq_date: {{req_date}}\nreq_sign: {{req_sign}}\n//Content-Length: application/json;charset=UTF-8\nContent-Type: application/json\n",
"pathVariables": {}
},
{
"id": "d78af170-fb97-47ac-a5ee-99ee6fddf741",
"name": "getAccess_token",
"url": "{{taxurl}}/AGG/oauth2/login",
"description": null,
"data": [],
"dataMode": "raw",
"headerData": [
{
"key": "Content-Type",
"value": "application/json"
}
],
"method": "POST",
"pathVariableData": [],
"queryParams": [],
"auth": null,
"events": [
{
"listen": "prerequest",
"script": {
"exec": [
""
],
"type": "text/javascript"
}
},
{
"listen": "test",
"script": {
"exec": [
"// 把responseBody转为json字符串\r",
"var data = JSON.parse(responseBody);\r",
"// 设置环境变量token,供后面的接口引用,位置就是上一步获取的位置\r",
"pm.environment.set(\"access_token\", data.value.access_token);\r",
"\r",
"console.log(\"test login access_token : \"+data.value.access_token)\r",
""
],
"type": "text/javascript"
}
}
],
"folder": null,
"rawModeData": "{\r\n \"grant_type\":\"client_credentials\",\r\n \"client_appkey\":\"{{client_appkey}}\",\r\n \"client_secret\":\"{{client_secret}}\"\r\n}\r\n",
"headers": "Content-Type: application/json\n",
"pathVariables": {}
},
{
"id": "ea5c3f97-156b-409f-9414-717743a89d7d",
"name": "getCa",
"url": "{{taxurl}}/AGG/org/getCa",
"description": null,
"data": [],
"dataMode": "raw",
"headerData": [
{
"key": "access_token",
"type": "text",
"value": "{{access_token}}"
},
{
"key": "req_date",
"type": "text",
"value": "{{req_date}}"
},
{
"key": "req_sign",
"type": "text",
"value": "{{req_sign}}"
},
{
"key": "Content-Length",
"type": "text",
"value": "application/json;charset=UTF-8",
"enabled": false
}
],
"method": "POST",
"pathVariableData": [],
"queryParams": [],
"auth": null,
"events": [
{
"listen": "prerequest",
"script": {
"exec": [
"pm.globals.set(\"req_date\",Math.round(new Date().getTime()) );\r",
"\r",
"//req_sign: API-SV1:<AppKey>:<Signature>\r",
"//req_sign \r",
"//签名值 = Base64(MD5(待签名字符串)))\r",
"//待签名字符串 = POST + \"_\" + Content-Md5 + \"_\" + req_date + \"_\" + access_token + \"_\" + AppSecret\r",
"var Content_Md5= CryptoJS.MD5(CryptoJS.enc.Utf8.parse(request.data)).toString();\r",
"var freq_sign = \"POST\" + \"_\" + Content_Md5 + \"_\" + pm.globals.get('req_date') + \"_\" +pm.environment.get(\"access_token\")+ \"_\" +pm.environment.get(\"AppSecret\");\r",
"var freq_signMD5= CryptoJS.MD5(freq_sign).toString();\r",
"\r",
"var freq_signBase64=CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(freq_signMD5));\r",
"\r",
"var Signature=freq_signBase64;\r",
"var req_sign=\"API-SV1:\"+pm.environment.get(\"client_appkey\")+\":\"+Signature;\r",
"pm.globals.set(\"req_sign\", req_sign);\r",
"\r",
"\r",
"var access_tokenTest= pm.environment.get(\"access_token\");\r",
"pm.globals.set(\"access_tokenTest\", access_tokenTest);\r",
"\r",
"pm.globals.set(\"freq_signMD5\", freq_signMD5);\r",
"pm.globals.set(\"request.data\", request.data);\r",
"pm.globals.set(\"client_appkey\", pm.environment.get(\"client_appkey\"));\r",
"pm.globals.set(\"access_token\", pm.environment.get(\"access_token\"));\r",
"pm.globals.set(\"req_sign\", req_sign);\r",
"\r",
"\r",
"\r",
" \r",
" "
],
"type": "text/javascript"
}
}
],
"folder": null,
"rawModeData": "{\r\n \"aggOrgId\": 1\r\n}",
"headers": "access_token: {{access_token}}\nreq_date: {{req_date}}\nreq_sign: {{req_sign}}\n//Content-Length: application/json;charset=UTF-8\n",
"pathVariables": {}
}
]
}