钉钉开发系列(七)媒体文件的上传与下载

官方提供的接口说明和示例是基于java的,却没有对具体的header作出更详细的说明,导致很难使用C#语言转换,几经测试,总算找到了个不是太完整的解决方法,代码如下。

/// <summary>
        ///POST文件
        /// </summary>
        /// <param name="url"></param>
        /// <param name="timeout"></param>
        /// <param name="fileKeyName">比如钉钉上传媒体文件使用的是media,该值用于服务端接收到数据时读取该keyname之后相关的数据。</param>
        /// <param name="fileBuffer">文件数据</param>
        /// <param name="fileName">文件名</param>
        /// <returns></returns>
        public static string Post(string url,
                                  string fileKeyName,
                                  byte[] fileBuffer,
                                  String fileName,
                                  int timeout)
        {

            var boundary = SecurityHelper.GenerateRadomStr();
            WebClient webClient = new WebClient();
            webClient.Headers.Add("Content-Type", string.Format("multipart/form-data; boundary={0}", boundary));
            string fileFormdataTemplate =
                            "
--" + boundary +
                            "
Content-Disposition:form-data;name="{0}";filename="{1}"" +
                            "
Content-Type:application/octet-stream" +
                            "

";
            string formDataHeader = String.Format(fileFormdataTemplate, "media", fileName);
            byte[] formDataHeaderBuffer = Encoding.UTF8.GetBytes(formDataHeader);

            string begin = $"--{boundary}
";
            byte[] beginBuffer = Encoding.UTF8.GetBytes(begin);

            string end = $"
--{boundary}--
";
            byte[] endBuffer = Encoding.UTF8.GetBytes(end); ;

            byte[] dataStream = new byte[formDataHeaderBuffer.Length + beginBuffer.Length + fileBuffer.Length + endBuffer.Length];
            formDataHeaderBuffer.CopyTo(dataStream, 0);
            beginBuffer.CopyTo(dataStream, formDataHeaderBuffer.Length);
            fileBuffer.CopyTo(dataStream, formDataHeaderBuffer.Length + begin.Length);
            endBuffer.CopyTo(dataStream, formDataHeaderBuffer.Length + begin.Length + fileBuffer.Length);
            var returnBuffer = webClient.UploadData(url, "POST", dataStream);
            Encoding encode = Encoding.UTF8;
            string resultJson = encode.GetString(returnBuffer);
            return resultJson;
        }


调用的代码

int timeout = 1000 * 60 * 5;
String resultJson = RequestHelper.Post(requestUrl, "media", fileBuffer, fileName, timeout);//media是固定的字符串
其中fileBuffer为文件的字节流,requestUrl按照接口的方式找接而成https://oapi.dingtalk.com/media/upload?access_token=ACCESS_TOKEN&type=TYPE。
目前测出,type=file时是可行的,type=image时不知为何总是提示【系统繁忙】,还请路过的大家们能够提供解决方案。

在上传成功后,需要再下载下来,下载时,由于成功和失败的返回数据不一样,所以需要先对前面的若干字节进行了试探处理,之后再依据试探结果继续处理,代码如下

附上读取媒体文件的方法
#region FetchMediaFile Function
        /// <summary>
        /// 获取媒体文件
        /// </summary>
        /// <param name="mediaId">媒体文件的id</param>
        /// <returns></returns>
        public static DDMediaFetchResult FetchMediaFile(string mediaId)
        {
            DDMediaFetchResult result = null;

            string apiurl = FormatApiUrlWithToken(Urls.media_get);
            apiurl = $"{apiurl}&{Keys.media_id}={mediaId}";
            WebClient webClient = new WebClient();
            var data = webClient.DownloadData(apiurl);

           int testHeaderMaxLength = 100;
        var testHeaderBuffer = new byte[(data.Length < testHeaderMaxLength ? data.Length : testHeaderMaxLength)];
            Array.Copy(data, 0, testHeaderBuffer, 0, testHeaderBuffer.Length);
            Encoding encoder = Encoding.UTF8;
            String testHeaderStr = encoder.GetString(testHeaderBuffer);
            if (testHeaderStr.StartsWith("--"))
            {//正常返回数据时,第一行数据为分界线,而分界线必然以"--"开始.
                var tempArr = testHeaderStr.Split(new String[] { Environment.NewLine }, StringSplitOptions.None);
                string boundary = tempArr[0] + Environment.NewLine;
                int boundaryByteLength = encoder.GetBytes(boundary).Length;
               byte[] destData = new byte[data.Length-boundaryByteLength];
           Array.Copy(data, boundaryByteLength, destData, 0, destData.Length);
           result = new DDMediaFetchResult();
           result.ErrCode = DDErrCodeEnum.OK;
           result.ErrMsg = "OK";
          result.Data = destData;

                const string Content_Length = "Content-Length";
                if (webClient.ResponseHeaders == null || (!webClient.ResponseHeaders.AllKeys.Contains(Content_Length)))
                {
                    result.FileLength = -1;
                }

                var lengthStr = webClient.ResponseHeaders[Content_Length];
                int length = 0;
                if (int.TryParse(lengthStr, out length))
                {
                    result.FileLength = length;
                }
                else
                {
                    result.FileLength = 0;
                }

                const string Content_Type = "Content-Type";
                if (webClient.ResponseHeaders == null || (!webClient.ResponseHeaders.AllKeys.Contains(Content_Type)))
                {
                    result.FileType = "unknown";
                }
                else
                {
                    result.FileType = webClient.ResponseHeaders[Content_Type];
                }
            }
            else
            {
                string resultJson = encoder.GetString(data);
                result = DDRequestAnalyzer.AnalyzeResult<DDMediaFetchResult>(resultJson);//将resultJson反序化为DDMediaFetchResult
            }
            return result;
        }
        #endregion

/// <summary>
    /// 媒体文件获取结果
    /// </summary>
    public class DDMediaFetchResult 
    {
    /// <summary>
        /// 错误码
        /// </summary>
    public int ErrCode{get;set;

        /// <summary>
        /// 错误消息
        /// </summary>
        public string ErrMsg { get; set; }}

        /// <summary>
        /// HTTP响应头
        /// </summary>
        public Dictionary<string, string> Header { get; set; }

        /// <summary>
        /// 获取的数据
        /// </summary>
        public byte[] Data { get; set; }

        /// <summary>
        /// 文件长度
        /// </summary>
        public int FileLength { get; set; }

        /// <summary>
        /// 文件类型
        /// </summary>
        public String FileType { get; set; }
                
    }
将收到的数据存成文件即可,比如将前面上传得到的mediaid传入后,下载得到了下面的图

附生成随机串的方法

   #region GenerateRadomStr
        /// <summary>
        /// 生成随机字符串
        /// </summary>
        /// <param name="length">随机串的长度</param>
        /// <returns></returns>
        public static string GenerateRadomStr(int length = 16)
        {
            string chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
            string str = "";
            Random rad = new Random();
            for (int i = 0; i < length; i++)
            {
                str += chars.Substring(rad.Next(0, chars.Length - 1), 1);
            }
            return str;
        }
        #endregion

欢迎打描左侧二维码打赏。

转载请注明出处。






原文地址:https://www.cnblogs.com/sparkleDai/p/7604924.html