最近在做一个微信项目,出于安全考虑业务系统是不对外公布的,但是微信是对外网公开的,于是决定在后台加一层通过内网去访问业务系统。
此次共使用了三台服务器,分别是云服务器,接口服务器和数据库服务器。其中云服务器部署微信,提供了一些暴露的 WebApi 供微信调用;接口服务器部署了业务系统的一些接口,供微信通过内网调用;数据库服务器可以由接口服务器通过内网访问到。
所以微信需要上传图片就需要云服务器的 WebApi 中转来调用接口服务器的附件上传接口。实现思路是微信前台通过 ajax 访问云服务器的 WebApi ,WebApi 接口获取 MEMI 内容的图片数据,然后将数据转发到接口服务器,从而实现将图片从用户手机传到接口服务器。
思路是对的,可是不知道怎么实现,研究了两周之后,看到“娃都会打酱油了”哥们的那篇:《WebAPI通过multipart/form-data方式接收文件时由开发自行决定如何保存文件》后恍然大悟。由于云服务器和接口服务器使用的都是使用 multipart/form-data 的方式来上传文件,所以在后台就使用了 MultipartFormDataStreamProvider 来保存文件。但是 MultipartFormDataStreamProvider 获取到了文件数据之后就自动保存了,很明细这不是我想要的效果,我不需要图片保存在云服务器,我需要图片保存在接口服务器。
“娃都会打酱油了”的哥们在《WebAPI通过multipart/form-data方式接收文件时由开发自行决定如何保存文件》的文章中介绍了怎么样使 MultipartFormDataStreamProvider 不自动保存图片,而是可以把图片数据读取出来之后自定义保存。
技术上具体实现思路是在微信前台通过 ajax 请求云服务器的 WebApi 接口中转上传图片,云服务器的 WebApi 通过 HttpClient 请求云服务器的文件上传接口。这里大致说一下,“娃都会打酱油了”哥们的文章告诉我们通过继承 MultipartStreamProvider,然后重载相关方法即可让 MultipartFormDataStreamProvider 不自动保存文件。具体代码请参考“娃都会打酱油了”哥们的文章,这里附上调用的代码和在 C# 后台调用 WebApi 接口实现文件上传的代码。
/// <summary>
/// 图片上传
/// </summary>
/// <returns></returns>
[HttpPost]
[Route("ImageUpload")]
[ActionName("ImageUpload")]
public async Task<HttpResponseMessage> ImageUpload()
{
IMGBLL bll = new IMGBLL();
var provider = new lib.MultipartFormDataStreamProvider();
try
{
await Request.Content.ReadAsMultipartAsync(provider);
Byte[] data = provider.FileContents[0].ReadAsByteArrayAsync().Result;
//File.WriteAllBytes(@"E:\杂项\1.jpg", data); //测试专用
return bll.ImageUpload(data);
}
catch (Exception ex)
{
return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, ex);
}
}
public static HttpResponseMessage FileUpload(String url, Byte[] data)
{
HttpResponseMessage responseResult = new HttpResponseMessage();
try
{
var handler = new HttpClientHandler()
{
AutomaticDecompression = System.Net.DecompressionMethods.GZip
};
using (var http = new HttpClient(handler))
{
using (var content = new MultipartFormDataContent())
{
var fileContent = new ByteArrayContent(data);
fileContent.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment") { FileName = "1.jpg" };
content.Add(fileContent);
responseResult = http.PostAsync(url, content).Result;
if (responseResult.StatusCode == System.Net.HttpStatusCode.Created)
{
Log.WriteLog("上传失败,状态码:" + responseResult.StatusCode + ",原因:" + responseResult.ReasonPhrase + ",错误信息:" + responseResult.Content.ToString());
}
}
}
}
catch (Exception ex)
{
Log.WriteLog("上传附件出错,URL:" + url + ",错误信息:" + ex.Message + ";堆栈信息:" + ex.StackTrace);
}
return responseResult;
}
这里特别需要注意的是要通过 MultipartFormDataContent 来进行附件上传。