调用说明
易荟通OPEN API 是使用 HTTP 并遵循 REST 原则设计的 Web 服务接口,您可以使用几乎任何客户端和任何编程语言与 REST API 进行交互。通过发送简单的 HTTP POST 请求就可以轻松接入使用。
统一请求格式#
BASE URL:#
https://gateway.yihuitong.topURL 格式:#
/openapi/{resource}/{function}说明:#
- {resource}为资源名,通常对应一类 API
- {function}为该资源提供的操作方法
比如发送短信的 url 为:https://gateway.yihuitong.top/openapi/sms/batchSend 表示调用 短信 的 批量发送 方法,返回 json 格式的字符串。 我们目前已经提供的接口,请参考 API。
HTTP 头信息:#
Accept:application/json;charset=utf-8; Content-Type:application/json;charset=utf-8; X-SIGNATURE: $signature; X-APIKEY: $APIKEY; X-TIMESTAMP: $timestamp; X-NONCE: $nonce;**说明#
上面带 $ 符号参数为变量对应下面表格说明
| 变量名称 | 说明 |
|---|---|
| $signature | 变量是接口验签值计算公式 signature = HMAC-SHAx-HEX(secret_key, signing_string) 从公式可以看出,想要获得签名需要得到 secret_key 和 signing_string 两个参数。 其中 secret_key 从 控制台->账号设置->APIKEY->secretKey 获取,signing_string 的计算公式为 signing_string = HTTP Method + \n + HTTP URI + \n + $APIKEY + \n + $timestamp + \n + $nonce + \n + canonical_query_string + \n + json_body |
| $APIKEY | 变量从 控制台->账号设置->APIKEY->apikey 获取 |
| $timestamp | 当前接口请求时的时间戳(精度到秒级) 跟易荟通服务器时间相差不能超过10秒 |
| $nonce | 变量是防重机制,请求时上次当前请求唯一ID; 推荐: 32-UUID、分布式ID |
- HTTP Method:指 HTTP 协议中定义的 GET、PUT、POST 等请求方法,必须使用全大写的形式。
- HTTP URI:要求必须以“/”开头,不以“/”开头的需要补充上,空路径为“/”。
- APIKEY: 请求头中的 X-APIKEY
- timestamp: 请求头中的 X-TIMESTAMP
- nonce: 请求头中的 X-NONCE
- canonical_query_string: 是对于 URL 中的 query( query 即 URL 中 ? 后面的 key1=valve1&key2=valve2 字符串)或者 Content-Type:application/x-www-form-urlencoded 的时候 body 里面的值,进行编码后的结果参数需要进行 url encode 编码 url_encode(key) + "=" + url_encode(value) 的形式,每一项转换后,以 key 按照字典顺序( ASCII 码由小到大)排序,并使用 & 符号连接起来,生成相应的 canonical_query_string 。 如果 没有query,canonical_query_string + \n 就不需要拼接上去
- json_body: POST 请求 Content-Type:application/json 的时候 json_body 就是 body 中的json请求数据
- HMAC-SHAx-HEX: 加密算法是 HmacSHA256 。 加密完后的字节数组需要在通过 Base64 进行编码
代码案例:#
根据下面的案例算出来headers的值是: {X-NONCE=bc9efee185e64ab9bc0b07a2785c4660, X-TIMESTAMP=1626856279, X-SIGNATURE=HB78nqGoplcCgZGInTYzEPjGyVy9/sm1uxQotqxo/6s=, X-APIKEY=123456789}
- Java
- Python
- C#
- PHP
import java.io.UnsupportedEncodingException;import java.net.URLEncoder;import java.security.InvalidKeyException;import java.security.NoSuchAlgorithmException;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;import java.util.TreeMap;import java.util.stream.Collectors;
import javax.crypto.Mac;import javax.crypto.spec.SecretKeySpec;import javax.xml.bind.DatatypeConverter;
import com.alibaba.fastjson.JSON;
public class SignatureCase { public static void main(String[] args) { @SuppressWarnings("unused") String smsUrl = "https://gateway.yihuitong.top/openapi/sms/batchSend"; String nonce = "bc9efee185e64ab9bc0b07a2785c4660"; Integer timestamp = 1626856279; String apikey = "123456789"; String secretKey = "1234567890"; String method = "POST"; String path = "/openapi/sms/batchSend"; String contentType = "json"; List<Map<String, String>> dataList = new ArrayList<>(); Map<String, String> dataMap = new HashMap<>(); dataMap.put("text", "【易荟通】尊敬的用户:您的验证码:707892,工作人员不会索取,请勿泄漏。"); dataMap.put("mobile", "11111111111"); dataList.add(dataMap); Map<String, Object> parameters = new HashMap<>(); parameters.put("data", dataList); StringBuilder sb = new StringBuilder(); sb.append(method).append("\n") .append(path).append("\n") .append(apikey).append("\n") .append(timestamp).append("\n") .append(nonce).append("\n"); if(parameters!=null && !parameters.isEmpty()) { if("json".equals(contentType) ) { sb.append(JSON.toJSONString(parameters)).append("\n"); }else { String canonical_query_string = formatUrlMap(parameters, true, false); sb.append(canonical_query_string).append("\n"); } } try { Mac hasher = Mac.getInstance("HmacSHA256"); hasher.init(new SecretKeySpec(secretKey.getBytes(), "HmacSHA256")); byte[] hash = hasher.doFinal(sb.toString().getBytes()); Map<String,String> headers = new HashMap<String, String>(); headers.put("X-SIGNATURE", DatatypeConverter.printBase64Binary(hash)); headers.put("X-APIKEY", apikey); headers.put("X-TIMESTAMP", timestamp.toString()); headers.put("X-NONCE", nonce); System.out.println(headers +": "+ headers); } catch (NoSuchAlgorithmException | InvalidKeyException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public static String formatUrlMap(Map<String, Object> paraMap,boolean urlEncode,boolean keyToLower) { if(paraMap==null || paraMap.isEmpty()) { return null; } if(!(paraMap instanceof TreeMap)) { paraMap = new TreeMap<String, Object>(paraMap); } return paraMap.entrySet().stream().map(entry -> { String key = entry.getKey(); Object value = entry.getValue(); if(urlEncode) { try { key = URLEncoder.encode(key, "utf-8"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } if(value!=null && !"".equals(value.toString())) { try { value = URLEncoder.encode(value.toString(), "utf-8"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } if (keyToLower) { key = key.toLowerCase(); } } return key + "=" + value; }).collect(Collectors.joining("&")); } }def hello_world(): print 'Hello, world!'//编译版本 4.0.30319.17929 for Microsoft (R) .NET Framework 4.5
using System;using System.Collections.Generic;using System.Linq;using System.Text.RegularExpressions;using Newtonsoft.Json;using System.Security.Cryptography;using System.Net;using System.IO;using System.Text;
namespace YiHuiTong{ public class Signature { public static void Main(string[] args) { string smsUrl = "https://gateway.yihuitong.top/openapi/sms/batchSend"; string nonce = System.Guid.NewGuid().ToString("N"); string timestamp = time(); string apikey = "123456789"; string secretKey = "1234567890"; string method = "POST"; string path = "/openapi/sms/batchSend"; Dictionary<string, string> dataMap = new Dictionary<string, string>(); dataMap.Add("text", "【易荟通】尊敬的用户:您的验证码:707892,工作人员不会索取,请勿泄漏。"); dataMap.Add("mobile","11111111111"); List<Dictionary<string, string>> dataList = new List<Dictionary<string, string>>(); dataList.Add(dataMap); Dictionary<string, Object> map = new Dictionary<string, Object>(); map.Add("data",dataList); string message = new HmacStringBuild(SigningHeadersContentType.JSON) .setMethod(method) .setPath(path) .setApikey(apikey) .setTimestamp(timestamp) .setNonce(nonce) .setData(map) .build(); Console.WriteLine(message); string SIGNATURE = CreateToken(message,secretKey); Console.WriteLine(SIGNATURE); Dictionary<string, string> headers = new Dictionary<string, string>(); headers.Add("X-SIGNATURE",SIGNATURE); headers.Add("X-TIMESTAMP",timestamp); headers.Add("X-APIKEY",apikey); headers.Add("X-NONCE",nonce); string returnData = Post(smsUrl,JsonConvert.SerializeObject(map).ToString(),headers); Console.WriteLine(returnData); } public static string CreateToken(string message, string secretKey) { secretKey = secretKey ?? ""; var encoding = new System.Text.UTF8Encoding(); byte[] keyByte = encoding.GetBytes(secretKey); byte[] messageBytes = encoding.GetBytes(message); using (var hmacsha256 = new HMACSHA256(keyByte)) { byte[] hashmessage = hmacsha256.ComputeHash(messageBytes); return Convert.ToBase64String(hashmessage); } } public static string time() { TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0); return Convert.ToInt64(ts.TotalSeconds).ToString(); } public static string formatUrlMap(Dictionary<string, Object> paraMap,bool urlEncode) { string para = ""; foreach (KeyValuePair<string, Object> kvp in paraMap) { string key = kvp.Key; string _value = kvp.Value.ToString(); if(urlEncode) { key = System.Web.HttpUtility.UrlEncode(key); if(_value!=null && _value.Length==0){ _value = System.Web.HttpUtility.UrlEncode(_value); } } para += key + "=" + _value + "&"; } return para.Substring(0,para.Length - 1); } public static string Post(string serviceUrl, string parameterData,Dictionary<string, string> headers) {
//创建Web访问对象 HttpWebRequest myRequest = (HttpWebRequest)WebRequest.Create(serviceUrl); //把用户传过来的数据转成“UTF-8”的字节流 byte[] buf = System.Text.Encoding.GetEncoding("UTF-8").GetBytes(parameterData);
myRequest.Method = "POST"; myRequest.Accept = "application/json"; myRequest.AutomaticDecompression = DecompressionMethods.GZip; myRequest.ContentType = "application/json; charset=UTF-8"; myRequest.ContentLength = buf.Length; myRequest.MaximumAutomaticRedirections = 1; myRequest.AllowAutoRedirect = true;
myRequest.Headers.Add("X-SIGNATURE", headers["X-SIGNATURE"]); myRequest.Headers.Add("X-TIMESTAMP", headers["X-TIMESTAMP"]); myRequest.Headers.Add("X-APIKEY", headers["X-APIKEY"]); myRequest.Headers.Add("X-NONCE", headers["X-NONCE"]);
//发送请求 Stream stream = myRequest.GetRequestStream(); stream.Write(buf, 0, buf.Length); stream.Close();
//通过Web访问对象获取响应内容 HttpWebResponse myResponse = (HttpWebResponse)myRequest.GetResponse(); //通过响应内容流创建StreamReader对象,因为StreamReader更高级更快 StreamReader reader = new StreamReader(myResponse.GetResponseStream(), Encoding.UTF8); //string returnXml = HttpUtility.UrlDecode(reader.ReadToEnd());//如果有编码问题就用这个方法 string returnData = reader.ReadToEnd();//利用StreamReader就可以从响应内容从头读到尾
reader.Close(); myResponse.Close();
return returnData; } } class HmacStringBuild { private SigningHeadersContentType contentType; private string method; private string path; private string apikey; private string timestamp; private string nonce; private Dictionary<string, System.Object> data; public HmacStringBuild(SigningHeadersContentType contentType){ this.contentType = contentType; } public HmacStringBuild setMethod(string method){ this.method = method; return this; } public HmacStringBuild setPath(string path){ this.path = path; return this; } public HmacStringBuild setApikey(string apikey){ this.apikey = apikey; return this; } public HmacStringBuild setTimestamp(string timestamp){ this.timestamp = timestamp; return this; } public HmacStringBuild setNonce(string nonce){ this.nonce = nonce; return this; } public HmacStringBuild setData(Dictionary<string, System.Object> data){ this.data = data; return this; } public string build(){ String str = this.method + "\n" + this.path + "\n" + this.apikey + "\n" + this.timestamp + "\n" + this.nonce + "\n"; if(string.Equals("GET",this.method)){ str = str + Signature.formatUrlMap(this.data,true) + "\n"; }else if(contentType == SigningHeadersContentType.JSON){ str = str + JsonConvert.SerializeObject(this.data) + "\n"; }else{ str = str + Signature.formatUrlMap(this.data,false) + "\n"; } return str; } } enum SigningHeadersContentType{ JSON,FORM };}<?php
function uuid() { $chars = md5(uniqid(mt_rand(), true)); $uuid = substr ( $chars, 0, 8 ) . '-' . substr ( $chars, 8, 4 ) . '-' . substr ( $chars, 12, 4 ) . '-' . substr ( $chars, 16, 4 ) . '-' . substr ( $chars, 20, 12 ); return $uuid ; } function http_post_data($url, $data_string, $header) {
echo json_encode($header); $ch = curl_init(); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_POSTFIELDS, $data_string); curl_setopt($ch, CURLOPT_HTTPHEADER, $header ); ob_start(); curl_exec($ch); $return_content = ob_get_contents(); ob_end_clean();
$return_code = curl_getinfo($ch, CURLINFO_HTTP_CODE); return array($return_code, $return_content); } $smsUrl = "https://gateway.yihuitong.top/openapi/sms/batchSend"; $nonce = uuid(); $timestamp = time(); $apikey = "123456789"; $secretKey = "1234567890"; $method = "POST"; $path = "/openapi/sms/batchSend"; $dataMap = array(['text'=> '【易荟通】尊敬的用户:您的验证码:707892,工作人员不会索取,请勿泄漏。','mobile'=> '11111111111']); $data = json_encode(array('data'=> $dataMap)); echo $data; $message = $method . "\n" . $path . "\n" . $apikey . "\n" . $timestamp . "\n" . $nonce . "\n" . $data . "\n";
$SIGNATURE = base64_encode(hash_hmac('sha256', $message, $secretKey,true)); // to base64
$header = array( 'X-SIGNATURE: ' . $SIGNATURE, 'X-TIMESTAMP: ' . $timestamp, 'X-APIKEY: ' . $apikey, 'X-NONCE: ' . $nonce, 'Content-Type: application/json; charset=utf-8', 'Content-Length: ' . strlen($data) );
list($return_code, $return_content) = http_post_data($smsUrl, $data, $header);
echo $return_code; echo $return_content;?>