JeffreySu / WeiXinMPSDK

微信全平台 .NET SDK, Senparc.Weixin for C#,支持 .NET Framework 及 .NET Core、.NET 8.0。已支持微信公众号、小程序、小游戏、微信支付、企业微信/企业号、开放平台、JSSDK、微信周边等全平台。 WeChat SDK for C#.
https://weixin.senparc.com
Apache License 2.0
8.33k stars 4.34k forks source link

下载微信对账单gzip格式时乱码 #670

Open qdesk opened 6 years ago

qdesk commented 6 years ago

( 此版块专为反馈bug及提交需求服务,不负责解答开发问题,请勿发表开发问题, 如果您需要这方面的帮助,请移步问答社区https://weixin.senparc.com/QA )

问题描述

1、我调用微信对账单sdk 返回的内容是 �{�hY�1480780492All2017-07-12.csv。我初步怀疑是编码问题,后来我用非gzip压缩的是正常的,很奇怪。那我就想是不是微信那边的问题。 2‘、如果返回是gzip格式是不是要自己再根据返回地址去下载对应的csv文件。

微信官方文档 URL

https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=9_6

发现问题的模块
模块对应的.net版本
开发环境
缓存环境
qdesk commented 6 years ago

试着修改了下源码,可能是腾讯gzip 压缩后这边解压 不对造成的乱码。

qdesk commented 6 years ago

修改了下代码不会出现乱码的问题,加了参数判断是不是gzip压缩 是给请求加上gzip头并启动gzip解压 写的不是很优雅。 ///

/// 使用Post方法获取字符串结果 /// /// /// /// /// 需要上传的文件,Key:对应要上传的Name,Value:本地文件名 /// /// 证书,如果不需要则保留null /// /// 验证服务器证书回调自动验证 /// 是否gzip压缩 /// /// public static string HttpPost(string url, CookieContainer cookieContainer = null, Stream postStream = null, Dictionary<string, string> fileDictionary = null, string refererUrl = null, Encoding encoding = null, X509Certificate2 cer = null, int timeOut = Config.TIME_OUT, bool checkValidationResult = false, bool isGzip = false) { HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); //是否gzip压缩 if (isGzip) { request.Headers["Accept-Encoding"] = "gzip,deflate"; request.AutomaticDecompression = DecompressionMethods.GZip; }

        request.Method = "POST";
        request.Timeout = timeOut;
        request.Proxy = _webproxy;
        if (cer != null)
        {
            request.ClientCertificates.Add(cer);
        }

        if (checkValidationResult)
        {
            ServicePointManager.ServerCertificateValidationCallback =
                new RemoteCertificateValidationCallback(CheckValidationResult);
        }

        #region 处理Form表单文件上传
        var formUploadFile = fileDictionary != null && fileDictionary.Count > 0;//是否用Form上传文件
        if (formUploadFile)
        {
            //通过表单上传文件
            postStream = postStream ?? new MemoryStream();

            string boundary = "----" + DateTime.Now.Ticks.ToString("x");
            //byte[] boundarybytes = Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\n");
            string fileFormdataTemplate = "\r\n--" + boundary + "\r\nContent-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\nContent-Type: application/octet-stream\r\n\r\n";
            string dataFormdataTemplate = "\r\n--" + boundary +
                                            "\r\nContent-Disposition: form-data; name=\"{0}\"\r\n\r\n{1}";
            foreach (var file in fileDictionary)
            {
                try
                {
                    var fileName = file.Value;
                    //准备文件流
                    using (var fileStream = FileHelper.GetFileStream(fileName))
                    {
                        string formdata = null;
                        if (fileStream != null)
                        {
                            //存在文件
                            formdata = string.Format(fileFormdataTemplate, file.Key, /*fileName*/ Path.GetFileName(fileName));
                        }
                        else
                        {
                            //不存在文件或只是注释
                            formdata = string.Format(dataFormdataTemplate, file.Key, file.Value);
                        }

                        //统一处理
                        var formdataBytes = Encoding.UTF8.GetBytes(postStream.Length == 0 ? formdata.Substring(2, formdata.Length - 2) : formdata);//第一行不需要换行
                        postStream.Write(formdataBytes, 0, formdataBytes.Length);

                        //写入文件
                        if (fileStream != null)
                        {
                            byte[] buffer = new byte[1024];
                            int bytesRead = 0;
                            while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
                            {
                                postStream.Write(buffer, 0, bytesRead);
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }
            //结尾
            var footer = Encoding.UTF8.GetBytes("\r\n--" + boundary + "--\r\n");
            postStream.Write(footer, 0, footer.Length);

            request.ContentType = string.Format("multipart/form-data; boundary={0}", boundary);
        }
        else
        {
            request.ContentType = "application/x-www-form-urlencoded";
        }
        #endregion

        request.ContentLength = postStream != null ? postStream.Length : 0;
        request.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8";
        request.KeepAlive = true;

        if (!string.IsNullOrEmpty(refererUrl))
        {
            request.Referer = refererUrl;
        }
        request.UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.57 Safari/537.36";

        if (cookieContainer != null)
        {
            request.CookieContainer = cookieContainer;
        }

        #region 输入二进制流
        if (postStream != null)
        {
            postStream.Position = 0;

            //直接写入流
            Stream requestStream = request.GetRequestStream();

            byte[] buffer = new byte[1024];
            int bytesRead = 0;
            while ((bytesRead = postStream.Read(buffer, 0, buffer.Length)) != 0)
            {
                requestStream.Write(buffer, 0, bytesRead);
            }

            //debug
            //postStream.Seek(0, SeekOrigin.Begin);
            //StreamReader sr = new StreamReader(postStream);
            //var postStr = sr.ReadToEnd();

            postStream.Close();//关闭文件访问
        }
        #endregion

        HttpWebResponse response = (HttpWebResponse)request.GetResponse();

        if (cookieContainer != null)
        {
            response.Cookies = cookieContainer.GetCookies(response.ResponseUri);
        }

        string retString = null;
        Stream responseStream = response.GetResponseStream();

        if (isGzip)
        {
            responseStream = new GZipStream(responseStream, CompressionMode.Decompress);
        }
        else
        {
            responseStream = response.GetResponseStream();
        }

        using (
            StreamReader myStreamReader = new StreamReader(responseStream,
                encoding ?? Encoding.GetEncoding("utf-8")))
        {
            retString = myStreamReader.ReadToEnd();

        } /*新增*/

        responseStream.Close();
        responseStream.Dispose();

        return retString;

    }

///

/// 对账单接口 /// https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_6 /// /// /// public static string DownloadBill(TenPayV3DownloadBillRequestData dataInfo) { var urlFormat = "https://api.mch.weixin.qq.com/pay/downloadbill"; var data = dataInfo.PackageRequestHandler.ParseXML(); var formDataBytes = data == null ? new byte[0] : Encoding.UTF8.GetBytes(data); MemoryStream ms = new MemoryStream(); ms.Write(formDataBytes, 0, formDataBytes.Length); ms.Seek(0, SeekOrigin.Begin);//设置指针读取位置 return RequestUtility.HttpPost(urlFormat, null, ms, encoding: Encoding.UTF8, isGzip: dataInfo.TarType == "GZIP"); }

JeffreySu commented 6 years ago

非常感谢!是否方便Pull Request到我们的Developer分支下面,方便我们审查代码?