记一次.net core调用微信云开发Http Api的uploadFile,上传文件到云环境的坑爹的排错过程

问题描述:使用微信云开发http api 上传文件,微信返回错误码400,结果格式是xml:

MalformedPOSTRequest The body of your POST request is not well-formed multipart/form-data. cos.ap-shanghai.myqcloud.com/6465-develop-0388d0-1258644315/test/test_1/userlist.csv NWRjMjg1OWFfZWFiYjFjMDlfMmI3NDdfY2M1NWQ4 OGVmYzZiMmQzYjA2OWNhODk0NTRkMTBiOWVmMDAxODc0OWRkZjk0ZDM1NmI1M2E2MTRlY2MzZDhmNmI5MWI1OTczMmZiNDZmZjBmNTVjMGU4NTViNDhhYWVjNzNkNzI4MzIyMTZjZTI0YWNhOTM4ZDlhNGM3NDA5MDQ1NjE3NTM=

过程和解决方法下文再表。

近一年来,想要弄个微信小游戏出来,但是苦于各种原因,总是断断续续,到现在还没有一个拿的出的作品。最近一段时间,看了微信云开发的相关文档,感觉有必要写个类库封装一下云Api,方便以后调用。于是就着手写了一个简单的调用库,过程中基本顺利。直到编写调用云存储,进行文件上传时,遇到了问题。而遍寻百度和谷歌,都没有找到相应的解决办法,所以想着把排错过程记录下来,以方便其他使用.net core 进行微信云开发的同学们进行讨论和参考。
笔者首先调用HTTP API的 uploadFile,成功的返回了数据,如图:
记一次.net core调用微信云开发Http Api的uploadFile,上传文件到云环境的坑爹的排错过程_第1张图片
以下为微信官方的要求:
记一次.net core调用微信云开发Http Api的uploadFile,上传文件到云环境的坑爹的排错过程_第2张图片
根据要求,代码实现如下(注意,下面这段代码不能正确上传,如果需要正确结果代码的,请拉到文末):

/// 
/// 上传文件
/// 
/// 云路径
/// 二进制文件
/// 
public BaseResult uploadFile(string path, byte[] fileBuff)
        {

            string resultContent = "";
            try
            {
                //获取文件上传链接和验证信息
                var uploadFilePathResult = getUploadFilePath(path);

                using (HttpClient client = new HttpClient())
                {
                    //client.BaseAddress = new Uri("http://localhost:52538/");
                    string boundary = "-----------" + DateTime.Now.Ticks.ToString("x");
                    var formContent = new MultipartFormDataContent(boundary);

                    formContent.Add(new StringContent(path), "\"key\"");
                    formContent.Add(new StringContent(uploadFilePathResult.authorization), "\"Signature\"");
                    formContent.Add(new StringContent(uploadFilePathResult.token), "\"x-cos-security-token\"");
                    formContent.Add(new StringContent(uploadFilePathResult.cos_file_id), "\"x-cos-meta-fileid\"");

                    var fileContent = new ByteArrayContent(fileBuff);
                    fileContent.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("form-data")
                    {
                        Name = "\"file\"",
                        FileName = "\"userlist.csv\""                         
                    };
                    fileContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("text/csv");
                    formContent.Add(fileContent);

                    formContent.Headers.Remove("Content-Type");
                    formContent.Headers.Add("Content-Type", "multipart/form-data; boundary=" + boundary);


                    var r = client.PostAsync(uploadFilePathResult.url, formContent).Result;
                    //var r = client.PostAsync("http://localhost:3000/post", formContent).Result;
                    var resultContentTask = r.Content.ReadAsStringAsync();
                    resultContentTask.Wait();
                    resultContent = resultContentTask.Result;

                }


            }
            catch (Exception e)
            {
            }
            var result = JsonConvert.DeserializeObject<BaseResult>(resultContent);
            return result;
        }

以上代码,笔者使用httpclient向微信提供的url推送验证信息和二进制文件。
但是当笔者使用测试用例,微信返回错误码400,结果格式是xml:

MalformedPOSTRequest The body of your POST request is not well-formed multipart/form-data. cos.ap-shanghai.myqcloud.com/6465-develop-0388d0-1258644315/test/test_1/userlist.csv NWRjMjg1OWFfZWFiYjFjMDlfMmI3NDdfY2M1NWQ4 OGVmYzZiMmQzYjA2OWNhODk0NTRkMTBiOWVmMDAxODc0OWRkZjk0ZDM1NmI1M2E2MTRlY2MzZDhmNmI5MWI1OTczMmZiNDZmZjBmNTVjMGU4NTViNDhhYWVjNzNkNzI4MzIyMTZjZTI0YWNhOTM4ZDlhNGM3NDA5MDQ1NjE3NTM=

大致的意思是我的Post请求的body不是格式正确的multipart / form-data。
于是笔者尝试了各种方式(中间省略一两千字。。。),花了半天的时间仍然找不到原因。
过程中,笔者用了Nodejs 的Express,建立了一个服务端,用于查看post过来的数据是否正确。服务端代码:

var express = require('express');  
var app = express();  
var multipart = require('connect-multiparty');  
  
var multipartMiddleware = multipart();  
app.post('/post', multipartMiddleware, function(req, res) {  
  res.header('Access-Control-Allow-Origin', '*');  
  console.log('get headers: ', req.headers);  
  console.log('get FormData Params: ', req.body);  
  
  res.json({result: 'success', data: req.body});  
}); 
app.listen(3000);

但是一直没有发现问题,Nodejs的服务端可以正确解释Post请求的body和file。
于是,笔者使用Postman,将微信返回的上传文件验证信息和验证信息,发送到微信服务器,发现竟然成功了!如下图:
记一次.net core调用微信云开发Http Api的uploadFile,上传文件到云环境的坑爹的排错过程_第3张图片
于是乎,连忙把Postman的请求地址改为Nodejs服务端地址,如图:
记一次.net core调用微信云开发Http Api的uploadFile,上传文件到云环境的坑爹的排错过程_第4张图片
再运行测试用例,将类库调用地址改为本地地址:
记一次.net core调用微信云开发Http Api的uploadFile,上传文件到云环境的坑爹的排错过程_第5张图片
分别向本地的nodejs服务端发送请求,并记录日志。
对两次请求的body和file进行对比,一直没发现问题。直到我打印出header信息,如下图:
记一次.net core调用微信云开发Http Api的uploadFile,上传文件到云环境的坑爹的排错过程_第6张图片
注意对比,看到什么不同了吗?
在这里插入图片描述
在这里插入图片描述
居然问题是出在content-type的boundary上!一个参数的值有用双引号括起来,一个没有。
所以问题是因为微信的服务端在解释multipart/form-data格式的时候,没有考虑到这种值带双引号的情况的(multipart/form-data格式请自行谷歌百度),而使用.net core 的MultipartFormDataContent类,默认会在boundary参数值加双引号。
问题终于真相大白了,所以接下来很简单,修改一下MultipartFormDataContent的Content-Type,重新提交,上传文件成功!
最终代码如下:

public BaseResult uploadFile(string path, byte[] fileBuff)
        {

            string resultContent = "";
            try
            {
                //获取文件上传链接和验证信息
                var uploadFilePathResult = getUploadFilePath(path);

                using (HttpClient client = new HttpClient())
                {
                    string boundary = "-----------" + DateTime.Now.Ticks.ToString("x");
                    var formContent = new MultipartFormDataContent(boundary);

                    formContent.Add(new StringContent(path), "\"key\"");
                    formContent.Add(new StringContent(uploadFilePathResult.authorization), "\"Signature\"");
                    formContent.Add(new StringContent(uploadFilePathResult.token), "\"x-cos-security-token\"");
                    formContent.Add(new StringContent(uploadFilePathResult.cos_file_id), "\"x-cos-meta-fileid\"");

                    var fileContent = new ByteArrayContent(fileBuff);
                    fileContent.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("form-data")
                    {
                        Name = "\"file\"",
                        FileName = "\"userlist.csv\""                         
                    };
                    fileContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("text/csv");
                    formContent.Add(fileContent);
                    //改写Content-Type
                    formContent.Headers.Remove("Content-Type");
                    formContent.Headers.Add("Content-Type", "multipart/form-data; boundary=" + boundary);


                    var r = client.PostAsync(uploadFilePathResult.url, formContent).Result;
                    //var r = client.PostAsync("http://localhost:3000/post", formContent).Result;
                    var resultContentTask = r.Content.ReadAsStringAsync();
                    resultContentTask.Wait();
                    resultContent = resultContentTask.Result;

                }


            }
            catch (Exception e)
            {
            }
            var result = JsonConvert.DeserializeObject<BaseResult>(resultContent);
            return result;
        }

你可能感兴趣的:(微信开发)