.net 调用csb服务完整教程(附加demo)

前言

官方文档只有java版的jdk和几个简陋的说明,并没有完整的demo。公司有一个.net项目需要对接csb服务,本人查看java的jdk源码和官方说明的实现了.net调用csb的完整代码。

csb接口说明

这里已http调用为例
调用csb接口参数分两部分
1 附加在header里参数

_api_timestamp:1592225468715    //时间戳
_api_name:http2http11       //服务名称
_api_signature:签名值       
_api_version:1.0.0        //版本
_api_access_key: ak123     //ccess_key
Content-Type:application/x-www-form-urlencoded;charset=UTF-8
复制代码

2 附加在报文body里或url里的参数(这里请自行参考webapi)
这里参数是业务请求参数是xml,json或x-www-form-urlencoded形式出现的
其中x-www-form-urlencoded参与签名计算xml,json不参与。


实现步骤如下

按请求方式分为get方式和post方式分开介绍,因为两种方式参数形式不一样。

get方式实现

第一步:声明一个配置类放ACCESS_KEY,SECRET_KEY,csb地址等

    public class Constants
    {
        public  const String ACCESS_KEY = "3212432dewewqadwr4532das";
    public const String SECRET_KEY = "232f321lYZ7wjrzdsaYeods12D4rdak=";
    public const String APP_KEY = "123456789";
    public const String CSB_ADDR = "http://ip/CSB";
        }
复制代码

第二步:签名方法实现(参考官方实现,其中有个坑点)


        public static string sign(string apiName, string apiVersion, long timeStamp, string accessKey, string secretKey, Dictionary<string, object[]> formParamDict, object body)
        {
            Dictionary<string, object[]> newDict = new Dictionary<string, object[]>();
            if (formParamDict != null)
            {
                foreach (KeyValuePair<string, object[]> pair in formParamDict)
                {
                    newDict.Add(pair.Key, pair.Value.Select(v => { return HttpUtility.UrlEncode(v.ToString()); }
                    ).ToArray());
                }
            }

            //设置csb要求的头参数,【将这四个参数+业务请求参数排序后签名】
            newDict.Add("_api_name", new String[] { apiName });
            newDict.Add("_api_version", new String[] { apiVersion });
            newDict.Add("_api_access_key", new String[] { accessKey });
            newDict.Add("_api_timestamp", new object[] { timeStamp });
****
            //对所有参数进行排序 
            //var sortedDict = from pair 
            //                 in newDict
            //                 orderby pair.Key
            //                 select pair;
            //【上面的是错误的请按照下面的方法实现】
          var  sortedDict = getSortByASCII(newDict); 
           StringBuilder builder = new StringBuilder();
            foreach (KeyValuePair<string, object[]> pair in sortedDict)
            {
                foreach (object obj in pair.Value)
                {
                    builder.Append(string.Format("{0}={1}&", pair.Key, obj));
                }
            }
            string str = builder.ToString();
            if (str.EndsWith("&"))
            {
                str = str.Substring(0, str.Length - 1); //去掉最后一个多余的 & 符号
            }
            System.Security.Cryptography.HMACSHA1 hmacsha = new System.Security.Cryptography.HMACSHA1
            {
                Key = Encoding.UTF8.GetBytes(secretKey)
            };
            byte[] bytes = Encoding.UTF8.GetBytes(str);
            return Convert.ToBase64String(hmacsha.ComputeHash(bytes));
        }
        
        ///排序方法,这里注意
         public static Dictionary<string, object[]> getSortByASCII(Dictionary<string, object[]> dict) {

            //这种排序是错误的
           // sortList.Sort((x, y) => {
               // var r = string.Compare(x.Key, y.Key);
                //return r;
          //  });
          //经过测试以下三种是正确的,会按照ASCII码排序
            var sortList = dict.ToList();
            sortList.Sort((x, y) => {

               return string.CompareOrdinal(x.Key, y.Key);
            });
            sortList.Sort((x, y) => {

                var r = string.Compare(x.Key, y.Key, StringComparison.Ordinal);
                return r;
            });
           
            Dictionary<string, object[]> sortDict = new Dictionary<string, object[]>();
            var keys = dict.Keys.ToArray();
            Array.Sort(keys, string.CompareOrdinal); //an
            foreach (var key in keys) {
                sortDict.Add(key, dict[key]);
            }
            return sortDict;

        }
复制代码

第三步组合请求报文,发送http的get请求
请求url和url参数(csb服务地址+业务参数):

Constants.CSB_ADDR?业务参数1=value1&业务参数2=value2

请求报文headers参数

_api_timestamp:1592225468715    //时间戳
_api_name:http2http11       //服务名称
_api_signature:签名值       
_api_version:1.0.0        //版本
_api_access_key: ak123     //ccess_key
Content-Type:application/x-www-form-urlencoded;charset=UTF-8

            //get时额外header(参考java_sdk源码还有以下几个额外的header参数)
            headerDic.Add("Accept-Encoding", "gzip");
            headerDic.Add("_inner_ecsb_request_id", "c0a8694816245153618221001d41d0");  //请求id随机一个\
            headerDic.Add("_inner_ecsb_rpc_id", "0");
            headerDic.Add("_inner_ecsb_trace_id", "c0a8694816245141995961002d3ef4"); // _inner_ecsb_trace_id随机一个\
复制代码

【注意时间戳实现】使用UnixTime

        public  static long ToUnixTimeMilliseconds(this DateTime nowTime) {

            DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1, 0, 0, 0, 0));
            long unixTime = (long)Math.Round((nowTime - startTime).TotalMilliseconds, MidpointRounding.AwayFromZero);
            return unixTime;
        }
复制代码

post方式实现

这个相对来说按文档就可以实现,同样注意签名时参数排序问题,时间戳的问题。

请求被url为:csb地址

业务请求参数:以json或者xml或者x-www-form-urlencoded放在请求body里(如果不清楚可自行查阅webapi相关教程)

headers参数,相比get秩序以下几个

_api_timestamp:1592225468715    //时间戳
_api_name:http2http11       //服务名称
_api_signature:签名值       
_api_version:1.0.0        //版本
_api_access_key: ak123     //ccess_key
Content-Type:application/x-www-form-urlencoded;charset=UTF-8
复制代码

坑点注意

  • c#默认参数排序与java不一致,需要按ascll排序
  • 时间戳 按unix格式获取
  • get方式参数要放在url里,记得value要url编码

demo地址

github.com/sccnice/net…

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享