HTTP请求规范

HTTP调用方式说明

本开放接口,针对合作接入方,以REST风格的HTTP服务接口方式,或模块界面集成方式,提供各种税务、财务、业务的相关能力服务。

客户系统可以根据自己系统的情况,选择不同的实现语言来实现对接。本文档以java为主要示例语言。

接口请求调用

1、Java语言推荐使用SDK来进行开发

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": {}
        }
    ]
}

results matching ""

    No results matching ""