RestSharp使用详解(3)OSS文件上传的问题

     基于前文中修改过的RestSharp我们已经可以轻松的调用OSS中大部分API如,GetService (ListBucket),Put Bucket,Get Bucket ACL,Delete Bucket等,接下来就到OSS最重要的操作了——Put Object ,即文件上传。

1、OSS PUT Object操作不兼容RFC1867文件上传协议

本以为上传操作会非常简单,根据文档代码我们可以调用以下几个方法添加文件

IRestRequest AddFile (string name, string path);
IRestRequest AddFile (string name, byte[] bytes, string fileName);
IRestRequest AddFile (string name, byte[] bytes, string fileName, string contentType);

我们第一版的代码就像下面一样了:

        public string PutObjectFromtFile(string bucket, string obj, string filePath)
        {
            var request = new RestRequest();
            request.Resource = "/" + bucket + "/" + obj;
            request.Method = Method.PUT;
            request.AddFile(obj, filePath);
            var response = Execute(request);
            return response.Headers.Where(m => m.Name == "ETag").First().Value.ToString().ToLower().Substring(1, 32);
        }

进行测试无奈又爆出400错误。我们接着Fiddler抓包,提交数据包结构如下,有部分省略:

Host: storage.aliyun.com
Content-Type: multipart/form-data; boundary=---------------------------122872775310383
Content-Length: 655
空行
 -----------------------------122872775310383
Content-Disposition: form-data; name="txt"

     通过查询得知:RestSharp的AddFile操作遵循了RFC1867协议,在上传文件时会添加额外的头文件进行分割。如同我们在浏览器中上传文件时必须在form中设置ENCTYPE必须为multipart/form-data。具体参考:通过解析HTTP协议自己实现文件上传。但是在阿里OSS服务中规定,PUT Object 操作使用PUT方法,并将文件以文件流方式添加到HTTP的body中。

     既然知道了原因我们接下来就进行修改,我们还是先看看Google讨论组上的有没有解决方法,找到一篇有用的帖子PUT's dont honor the RequestFormat ,接下来就对RestSharp大刀阔斧的改造了。

改造思路如下,首先为添加一个属性,用来标识是否上传原始文件流;然后找到构造multipart协议的代码,根据属性来确定是否上传原始文件。

我么先找到了添加文件的位置位于Http.cs文件中:

        private void WriteMultipartFormData(Stream requestStream)
        {
                foreach (var param in Parameters)
                {
                    WriteStringTo(requestStream, GetMultipartFormData(param));
                }

                foreach (var file in Files)
                {
                    // Add just the first part of this param, since we will write the file data directly to the Stream
                    WriteStringTo(requestStream, GetMultipartFileHeader(file));

                    // Write the file data directly to the Stream, rather than serializing it to a string.
                    file.Writer(requestStream);
                    WriteStringTo(requestStream, _lineBreak);
                }

                WriteStringTo(requestStream, GetMultipartFooter());
}

我们Http类实现了IHttp接口,我们添加UploadRaw属性在IHttp接口中,并将上面代码改为:

        private void WriteMultipartFormData(Stream requestStream)
        {
            if (!UploadRaw)
            {
                foreach (var param in Parameters)
                {
                    WriteStringTo(requestStream, GetMultipartFormData(param));
                }
                foreach (var file in Files)
                {
                    // Add just the first part of this param, since we will write the file data directly to the Stream
                    WriteStringTo(requestStream, GetMultipartFileHeader(file));

                    // Write the file data directly to the Stream, rather than serializing it to a string.
                    file.Writer(requestStream);
                    WriteStringTo(requestStream, _lineBreak);
                }

                WriteStringTo(requestStream, GetMultipartFooter());
            }
            else
            {
            //写入原始文件流
                var file = Files.First();
                file.Writer(requestStream);
            }
        }

初始化Http类的代码在RestClient类中

private void ConfigureHttp(IRestRequest request, IHttp http)

代码太多,就不粘贴了,从上面方法中我们的看出来http的属性实际是根据request的值构造的。因此我们还需要在IRestRequest添加一个属性,否则没有办法赋值,同样添加UploadRaw属性。并在ConfigureHttp方法中添加一行 http.UploadRaw=request.UploadRaw即可。
改造完毕看看我们现在的文件上传方法:

        public string PutObjectFromtFile(string bucket, string obj, string filePath)
        {
            var request = new RestRequest();
            request.Resource = "/" + bucket + "/" + obj;
            request.Method = Method.PUT;
            request.AddFile(obj, filePath);
            //关键在这里
            request.UploadRaw = true;
            var response = Execute(request);
            return response.Headers.Where(m => m.Name == "ETag").First().Value.ToString().ToLower().Substring(1, 32);
        }

至此,我们OSS API的全部操作都可以顺利的完成了。希望对用到RestSharp的朋友有帮助。

posted @ 2012-05-22 13:11  我是小马  阅读(3473)  评论(4编辑  收藏  举报