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

  • 相关阅读:
    NSInvalidArgumentException', reason: '[__NSCFDictionary setObject:forKey:]: attempt to insert nil value (key: WebKitLocalStorageDatabasePathPreferenc
    Mac下Android开发环境的搭建
    Xcode 4.4 的新特性 | LLVM 4.0 的新语法
    UIButton设置 textAlignment 属性的方法
    ipa包中图片进行了Compress之后的主要处理和作用
    苹果开发者证书的申请流程 Apple ID for IDP..
    systemtap perf 火焰图
    pg_blocking pg_monitor (转) postgresql表死锁问题的排查方式 阻塞分析 慢SQL
    知识广度 vs 知识深度
    火焰图入门
  • 原文地址:https://www.cnblogs.com/yanyan45/p/2511390.html
Copyright © 2011-2022 走看看