RestSharp使用詳解(2)RestSharp的BUG和不足


     書接上文,按照上篇文章的基礎類搭建起運行環境后,你可能會發現,請求OSS服務報錯,至少我是這樣的。經過Fiddler抓包分析后發現http請求中根本沒有Dat文檔中要求的Date字段。

1、HTTP協議頭中的Date字段

     發現有這個問題后立馬上Google Group看看是否為RestSharp的bug。討論組上給的答復很無語啊。

This is a bug. There is currently a pull request for this. https://github.com/restsharp/RestSharp/pull/275 
This will only be supported in .NET 4.0, when the next version ships(no timeline).

 看來是可以解決的。首先查看上面鏈接的代碼,仔細看在http頭設置中有一下代碼,其中r為System.Net.HttpWebRequest類型,v為要設置的值:

#if NET4 
    _restrictedHeaderActions.Add("Date", (r, v) => 
       { 
       DateTime parsed; 

       if (DateTime.TryParse(v, out parsed)) 
        { 
       r.Date = parsed; 
         } 
  }); 
 _restrictedHeaderActions.Add("Host", (r, v) => r.Host = v); 
#else 

原來的代碼:

			_restrictedHeaderActions.Add("Date", (r, v) => { /* Set by system */ });
			_restrictedHeaderActions.Add("Host", (r, v) => { /* Set by system */ });

我們查看MSDN對於Headers中對Date和Host的說明http://msdn.microsoft.com/zh-cn/library/system.net.httpwebrequest.headers(v=vs.80)

.NET Framework 2.0-3.5中說明:

Date

由系統設置為當前日期。

Host

由系統設置為當前主機信息。

.NET Framework 4.0-4.5

Date

Date 屬性設置。

宿主

Host 屬性設置。

由於RestSharp默認的編譯目標框架為.NET Framework3.5 Client Profile ,HttpWebRequest是沒有Date和Host屬性的。猜測我們在.Net 4.0環境下運行此原版后造成Date屬性未設置,因此http請求中沒有Date字段。

解決方法1:編譯框架改為.NET Framework4。然后按上面的代碼進行修改

解決方法2:通用方法適用於.NET 2.0 4.0——利用反射機制

代碼如下:

            _restrictedHeaderActions.Add("Date", (r, v) =>
            { /* Set by system */
                float dotnetVersion = float.Parse(DetermineFramework());
                if (dotnetVersion >= 4.0)
                {
                    PropertyInfo pinfo = r.GetType().GetProperty("Date");
                    pinfo.SetValue(r, DateTime.Parse(v).ToUniversalTime(), null);
                }
                else
                {
                    Type type = r.Headers.GetType();
                    MethodInfo method = type.GetMethod("AddWithoutValidate",
                        BindingFlags.Instance | BindingFlags.NonPublic);
                    method.Invoke(r.Headers, new[] { "Date", v });
                }
            });

通過上面的代碼我們很的解決了Date頭的設置問題了~

2、Parameter 參數的生命周期和使用方法

     我們首先看一下Restsharp中Parameter類型的定義和使用方式,在Parameter類型中Type屬性用來定義可以添加到http協議的參數的類型:

View Code
    public class Parameter
    {
        /// <summary>
        /// Name of the parameter
        /// </summary>
        public string Name { get; set; }
        /// <summary>
        /// Value of the parameter
        /// </summary>
        public object Value { get; set; }
        /// <summary>
        /// Type of the parameter
        /// </summary>
        public ParameterType Type { get; set; }

        /// <summary>
        /// Return a human-readable representation of this parameter
        /// </summary>
        /// <returns>String</returns>
        public override string ToString() {
            return string.Format("{0}={1}", Name, Value);
        }
    }

重點關注一下ParameterType枚舉:

public enum ParameterType
{
    Cookie,
    GetOrPost,
    UrlSegment,
    HttpHeader,
    RequestBody
}

對於Cookie HttpHeader和RequestBody就沒有什么好說的了都是http的基本組成部分,我們主要關注GetOrPost和UrlSegment類型

1、GetOrPost

     我們知道http協議中有兩種基本的協議Get協議和Post協議,在Get協議中通過URL中的QueryString來將參數對發送到服務器即:url?name1=value1&name2=value2。在Post協議中將參數構成name1=value1&name2=value2形式,然后放在http的Body中。

當Parameter的類型設置為GetOrPost的時候,會根據Request.Method的類型來決定參數的位置。那么我們就會產生以下疑問對於非Post和Get方法,比如PUT,Delete參數放在什么位置呢?,如果想在Post中添加QueryString如何處理?那么就要應用到UrlSegment了。

2、UrlSegment

UrlSegment是起到應用中占位的作用,在執行請求時{entity}將被替換

var rq = new RestRequest("health/{entity}/status");
rq.AddParameter("entity", "s2", ParameterType.UrlSegment);

拿OSS實例做講解,我們實現一個Bucket的Delete方法:

        public void DeleteBucket(string bucket)
        {
            if (!Utils.ValidateBucketName(bucket))
            {
                throw new ArgumentException("Unsupported bucket name:"
                        + bucket);
            }
            var request = new RestRequest();
            request.Resource = "/{bucket}/";
            request.AddParameter("bucket",bucket, ParameterType.UrlSegment);
       //上面好看,但是不中用啊!
       // request.Resource = "/" + bucket + "/";
request.Method
= Method.DELETE; var response = Execute(request); }

本以為萬事大吉了,然而服務器端卻報來錯誤,“SignatureDoesNotMatch”!這下郁悶了,算法簽名應該沒有問題啊!,我們跟蹤簽名算法類型AliyunAuthenticator;

行 38   :           string resource = request.Resource;

此時的值為“/{bucket}/”,無奈此時UrlSegment並沒有被替換為真正地url,因此簽名也是錯誤的,看來UrlSegment並不是那么好用的,直接寫為:

request.Resource = "/" + bucket + "/";還是實用一些。

最后,想在請求中實用QueryString參數,還是直接寫在Resource屬性里面吧,如:request.Resource = "/" + bucket + "/?acl";。看來UrlSegment好看但是不中用。

以上都是在調用OSS API上遇到的問題,有些問題沒有深入分析,還請指正,下一篇會分析我在實用文件上傳時遇到的問題!


免責聲明!

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



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