RestSharp使用詳解(1)調用阿里巴巴開放存儲服務


     看了張善友老師的幾篇文章后決定認真學習一下Restfull風格的API開發和調用,於是先選用了RestSharp 作為客戶端進行練習。調用的服務為阿里巴巴提供的開放存儲服務。

阿里巴巴雲存儲服務提供了50G的免費空間以及每個月10G的流量,非常適合我們做點小應用。具體的API規則請查閱OSS存儲服務開發文檔

1、推薦的使用方式

直接上代碼啦~

    public class AliyunApi
    {
        const string BaseUrl = "http://storage.aliyun.com";

        readonly string _accountSid;
        readonly string _secretKey;

        public AliyunApi(string accountSid, string secretKey)
        {
            _accountSid = accountSid;
            _secretKey = secretKey;
        }
        //返回的XML或Josn對象直接反序列為實體對象
        public T Execute<T>(RestRequest request) where T : new()
        {
            var client = new RestClient();
            client.BaseUrl = BaseUrl;
            client.Authenticator = new AliyunAuthenticator(_accountSid, _secretKey);

            string date = DateTime.UtcNow.ToString("r");
            request.AddHeader(Constants.DATE, date);
            var response = client.Execute<T>(request);
            if ((int)response.StatusCode / 100 != 2)
            {
                throw new OssException(response);
            }
            return response.Data;
        }
     //返回信息沒有Body的對象
public IRestResponse Execute(RestRequest request) { var client = new RestClient(); client.BaseUrl = BaseUrl; client.Authenticator = new AliyunAuthenticator(_accountSid, _secretKey); string date = DateTime.UtcNow.ToString("r"); request.AddHeader(Constants.DATE, date); var response = client.Execute(request); if ((int)response.StatusCode / 100 != 2) { throw new OssException(response); } return response; } //列出所有的Bucket public ListAllMyBucketsResult ListAllMyBuckets() { var request = new RestRequest(); request.Resource = "/"; request.Method = Method.GET; //request.AddParameter("CallSid", callSid, ParameterType.UrlSegment); return Execute<ListAllMyBucketsResult>(request); }      //創建一個Bucket
public void PutBucket(string bucket, string per) { if (!Utils.ValidateBucketName(bucket)) { throw new ArgumentException("Unsupported bucket name:" + bucket); } var request = new RestRequest(); request.Resource = "/" + bucket + "/"; request.Method = Method.PUT; request.AddHeader(Constants.ACL, per); var response = Execute(request); } }

上面定義了兩個Execute方法,一個可以返回泛型結果T一個用於沒有返回實體對象操作的。下面分別定義了ListAllMyBuckets來列出我所創建的所有Bucket,PutBucket用於創建一個新的Bucket。

2、錯誤處理

細心的朋友一定注意到了返回錯誤的處理方式:

            if ((int)response.StatusCode / 100 != 2)
            {
               
throw new OssException(response);
            }
在RestSharp的HttpResponse 類型中定義了兩個有關Http狀態的字段分別為:

1:System.Net.HttpStatusCode枚舉類型的StatusCode

2:RestSharp.ResponseStatus枚舉類型的ResponseStatus

除網絡連接失敗,DNS請求失敗等原因ResponseStatus均為 Completed。

HttpStatusCode才是用來描述web服務器發回來的狀態,也就是我們常說的200、301、404、500等http頭。

System.Net.HttpStatusCode 在定義中關於200的一共有一下7種

        OK = 200,
        Created = 201,
        Accepted = 202,
        NonAuthoritativeInformation = 203,
        NoContent = 204,
        ResetContent = 205,
        PartialContent = 206,

也就是說200以內的都是成功的請求,因此單純判斷(response.StatusCode==HttpStatusCode.OK),可能出現意外。

3、自定義驗證

自定義驗證相對簡單了,根據OSS文檔要求就可以了代碼如下:

View Code
    public class AliyunAuthenticator : IAuthenticator
    {
        private const string DEFINE_PREFIX = "x-oss-";
        private const string ALGORITHM = "HmacSHA1";

        private readonly string accessKeyId;
        private readonly string secretAccessKey;

        public AliyunAuthenticator(string accessKeyId, string secretAccessKey)
        {
            this.secretAccessKey = secretAccessKey;
            this.accessKeyId = accessKeyId;
        }
        public void Authenticate(IRestClient client, IRestRequest request)
        {
            IEnumerable<Parameter> headers = request.Parameters.Where(m => m.Type == ParameterType.HttpHeader);
            IDictionary<string, string> dHeaders = new Dictionary<string, string>();

            foreach (Parameter p in headers)
            {
                dHeaders.Add(p.Name, p.Value.ToString());
            }


            if (!string.IsNullOrEmpty(secretAccessKey) && !string.IsNullOrEmpty(accessKeyId))
            {
                string resource = request.Resource;
                if(request.Resource.IndexOf("client.BaseUrl")>0)
                    resource = request.Resource.Remove(0, client.BaseUrl.Length);
                string authValue = "OSS "
                     + this.accessKeyId
                     + ":"
                     + GetAssign(secretAccessKey, request.Method.ToString(), dHeaders, resource);

                request.AddHeader(Constants.AUTHORIZATION, authValue);
            }
            else if (!string.IsNullOrEmpty(accessKeyId))
            {
                request.AddHeader(Constants.AUTHORIZATION, accessKeyId);
            }
        }

        private static string GetAssign(string secretAccessKey, string method,
            IDictionary<string, string> headers, string resource)
        {
            StringBuilder canonicalizedOssHeaders = new StringBuilder();
            StringBuilder stringToSign = new StringBuilder();
            byte[] byteHMAC = null;
            string contentMd5 = SafeGetElement(Constants.CONTENT_MD5, headers);
            string contentType = SafeGetElement(Constants.CONTENT_TYPE, headers);
            string date = SafeGetElement(Constants.DATE, headers);
            string canonicalizedResource = resource;


            SortedDictionary<string, string> tmpHeaders = formatHeader(headers);
            if (tmpHeaders.Count > 0)
            {
                foreach (string key in tmpHeaders.Keys)
                {
                    if (key.ToLower().StartsWith(DEFINE_PREFIX))
                    {
                        canonicalizedOssHeaders.Append(key).Append(":")
                                .Append(tmpHeaders[key]).Append("\n");
                    }
                }
            }
            stringToSign.Append(method).Append("\n").Append(contentMd5)
                    .Append("\n").Append(contentType).Append("\n").Append(date)
                    .Append("\n").Append(canonicalizedOssHeaders)
                    .Append(canonicalizedResource);
            try
            {
                Encoding encoding = ASCIIEncoding.GetEncoding(Constants.CHARSET);
                byte[] keyBytes = encoding.GetBytes(secretAccessKey);
                KeyedHashAlgorithm hmac = KeyedHashAlgorithm.Create(ALGORITHM);
                hmac.Key = keyBytes;
                byteHMAC = hmac.ComputeHash(encoding.GetBytes(stringToSign.ToString()));
            }
            catch (Exception e)
            {
            }
            return Convert.ToBase64String(byteHMAC);
        }

        private static SortedDictionary<string, string> formatHeader(
        IDictionary<string, string> headers)
        {
            SortedDictionary<string, string> tmpHeaders = new SortedDictionary<string, string>();

            foreach (string key in headers.Keys)
            {
                if (key.ToLower().StartsWith(DEFINE_PREFIX))
                {
                    tmpHeaders[key.ToLower()] = headers[key];
                }
                else
                {
                    tmpHeaders[key] = headers[key];
                }
            }
            return tmpHeaders;
        }

        private static string SafeGetElement(string key, IDictionary<string, string> map)
        {
            if (map == null || !map.ContainsKey(key))
            {
                return "";
            }
            return map[key];
        }
    }

上面只是把基本的結構分析了一下,看似簡單,在應用過程中,遇到了很多麻煩。下一篇在分析使用過程中遇到的具體問題了,歡迎拍磚。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM