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的朋友有帮助。

你可能感兴趣的:(REST)