【C#】利用HttpClient上传文件到网站服务器和办理出错问题 ...

打印 上一主题 下一主题

主题 1927|帖子 1927|积分 5781

第一次利用HttpClient上传文件到网站服务器时,尤其是假如长时间未进行操作,利用Https加密传输协议可能会遇到一些错误。针对这些潜在的问题,以下是一些办理方案,以帮助您顺遂上传文件。

  
选择文件

比方,点击上传文件按钮,通过打开文件对话框来选择文件, 代码如下
  1. var dialog = new Microsoft.Win32.OpenFileDialog();
  2. dialog.Title = "选择上传的文件";
  3. dialog.CheckFileExists = true;
  4. dialog.Filter = "*.zip(压缩文件)|*.zip";
  5. dialog.Multiselect = false;
  6. if (dialog.ShowDialog() == true)
  7. {
  8.     DoUploadFileAsync(dialog.FileName).ContinueWith(res => {
  9.         Debug.WriteLine($"responseText: {res.Result}");
  10.     });
  11. }
复制代码
接下来实现上传文件的异步方法DoUploadFileAsync,输出返反响应的效果res.Result
上传文件

实现异步方法DoUploadFileAsync,利用HttpClient上传文件, 代码如下
  1. internal async Task<string> DoUploadFileAsync(string filePath)
  2. {
  3.     try
  4.     {
  5.         var url = API_BASE_URL + "/Default.aspx?type=uploadfile";
  6.                 //System.Net.ServicePointManager.Expect100Continue = true;
  7.         //System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Tls12 | System.Net.SecurityProtocolType.Tls11 | System.Net.SecurityProtocolType.Tls;
  8.         using (var client = new HttpClient())
  9.         {
  10.             //client.Timeout = TimeSpan.FromSeconds(10);
  11.             //client.DefaultRequestHeaders.Add("Referer", API_BASE_URL + "/");
  12.                         using (var formData = new MultipartFormDataContent())
  13.                         {
  14.                             using (var fileStream = new System.IO.FileStream(filePath, System.IO.FileMode.Open, System.IO.FileAccess.Read))
  15.                             {
  16.                                 var fileName = System.IO.Path.GetFileName(filePath);
  17.                                 using (var streamContent = new StreamContent(fileStream, (int)fileStream.Length))
  18.                                 {
  19.                                     //上传文件处理方式省略...
  20.                        
  21.                                     using (var response = await client.PostAsync(url, formData))
  22.                                     {
  23.                                         if (response.IsSuccessStatusCode)
  24.                                         {
  25.                                             return await response.Content.ReadAsStringAsync();
  26.                                         }
  27.                                         else
  28.                                         {
  29.                                             throw new Exception(">>> DoUploadFileAsync NoSuccessStatusCode");
  30.                                         }
  31.                                     }
  32.                                 }
  33.                             }
  34.                         }
  35.         }
  36.     }
  37.     catch(Exception ex)
  38.     {
  39.         Debug.WriteLine($">>>> DoUploadFileAsync Error:{ex.Message} \nStackTrace:{ex.StackTrace}");//发生一个或多个错误。
  40.     }
  41.     return string.Empty;
  42. }
复制代码
  上传地点若是加密传输https协议, 就要设置 System.Net.ServicePointManager.SecurityProtocol 利用安全证书
  ContentType

在上传文件处理方式中,利用差别的文件内容类型,
multipart/form-data

当利用内容类型为"multipart/form-data",代码如下
  1. var fileContent = new ByteArrayContent(streamContent.ReadAsByteArrayAsync().Result);
  2. fileContent.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("multipart/form-data");
  3. formData.Add(fileContent, "file", fileName);
  4. // 如果需要添加其他表单字段,可以继续添加,注意key与value对应
  5. // form.Add(new StringContent("value"), "key");
复制代码
上传文件时,配景服务器可能响应错误消息,提示路径包含非法字符,
   大致可能是文件名有包含中文时乱码引起的,因此以上方法不实用,
  application/octet-stream

当利用内容类型为application/octet-stream,改成如下
  1. streamContent.Headers.Add("Content-Type", "application/octet-stream");
  2. var bytes = Encoding.UTF8.GetBytes($"form-data; name="file"; filename="{fileName}"");
  3. var headerValue = ;
  4. foreach (var b in bytes) headerValue += (Char)b;
  5. streamContent.Headers.Add("Content-Disposition", headerValue);
  6. formData.Add(streamContent, "file", fileName);
复制代码
  以上方法,可防止中文的文件名乱码
  报错问题

关于上传出现报错的问题收集
无法访问对象

   报错:无法访问已开释的对象。
  看对象名是什么,可能是“System.Net.Http.MultipartFormDataContent”,
这是因为在调用异步时,又调用了一次,调用之前就已主动开释了被引用的对象,
适当利用using () {} 可管理对象在不消时被开释
未同步执行非常

   报错:System.Threading.Tasks.Task 1.GetResultCore(Boolean waitCompletionNotification)
  可能是执行以下同步代码造成的,
  1. var responseText = client.PostAsync(url, formData).GetAwaiter().GetResult().Content.ReadAsStringAsync().Result;
复制代码
试试改成async和await调用方式,保证同步执行
建立安全通道

   报错:根本毗连已经关闭: 未能为 SSL/TLS 安全通道建立信任关系。
  当请求地点API_BASE_URL是带https协议,那可能会报错安全通道信任问题的非常,
在新建的HttpClientHandler实例设置一个事件,信任所有证书
  1. var hander = new HttpClientHandler();
  2. hander.ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => {
  3.     // 在这里添加你的证书验证逻辑
  4.     // 返回true来表示允许所有证书(不推荐用于生产环境)
  5.     return true;
  6. };
复制代码
用于生产情况这会不安全,要改利用 System.Net.ServicePointManager.SecurityProtocol,
可能还会报错, 就试试改成如下代码
  1. var hander = new HttpClientHandler();
  2. hander.AllowAutoRedirect = true;
  3. hander.UseCookies = true;
  4. hander.CookieContainer = cookies;
  5. hander.ClientCertificateOptions = ClientCertificateOption.Automatic;
复制代码
  通过设置ClientCertificateOptions 利用安全认证…
  末了,将hander传给client即可
  1. var client = new HttpClient(hander);
  2. //...
复制代码
接收文件

假如还没有实现接收文件, 这里就在本地服务器上实现一下, 方便测试
   配景服务器的开辟语言种类繁多, 这里利用一种开辟语言C#,
  写一个例子, 实现接收文件
.Net Aspx

比方,在Default.aspx页面里实现上传文件,再到配景处理请求接收文件,
上传文件页面内容如下,
  1. <form>
  2.         <h1>上传文件</h1>
  3.         <hr />
  4.         <div>
  5.             <input type="file" name="file"/>
  6.         </div>
  7.     <hr />
  8. </form>
  9. <script>
  10.         $(function () {
  11.         $('input[type=file]:last').on('change', onChange);
  12.     })
  13.     function onChange(e) {
  14.         var btn = $('form:last');
  15.         var file = btn[0];
  16.         var data = new FormData(file);
  17.         $.ajax({
  18.             url:'/Default.aspx?type=uploadfile',
  19.             type: 'POST',
  20.             data: data,
  21.             cache: false,
  22.             processData: false,
  23.             contentType: false,//改变默认string类型'application/json; charset=utf-8'
  24.             success: function (res) {
  25.                 console.log('ajax success', res);
  26.             },
  27.             error: function (err) {
  28.                 console.error('ajax error', err)
  29.             }
  30.         })
  31.     }
  32. </script>
复制代码
  这里利用怀旧主流的前端框架jQuery, 它的网上免费学习文档丰富
  在配景的处理接收文件,调用方法UploadFile(),代码如下
  1. private string UploadFile()
  2. {
  3.     if (Request.Files.Count > 0)
  4.     {
  5.         var file = Request.Files[0];
  6.         var fileName = System.IO.Path.GetFileName(file.FileName);
  7.         var path = System.IO.Path.Combine(Server.MapPath("~/Uploads/"), fileName);
  8.         file.SaveAs(path);
  9.         return "ok";
  10.     }
  11.     return "fail";
  12. }
复制代码
写到这里为止,期待下次再见!


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

西河刘卡车医

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表