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上遇到的问题,有些问题没有深入分析,还请指正,下一篇会分析我在实用文件上传时遇到的问题!

posted @ 2012-05-21 13:00  我是小马  阅读(4708)  评论(0编辑  收藏  举报