【C#】使用HttpClient上传文件到网站服务器和解决出错问题

07-19 934阅读

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

文章目录

  • 选择文件
  • 上传文件
    • ContentType
      • multipart/form-data
      • application/octet-stream
      • 报错问题
        • 无法访问对象
        • 未同步执行异常
        • 建立安全通道
        • 接收文件
          • .Net Aspx

            选择文件

            例如,点击上传文件按钮,通过打开文件对话框来选择文件, 代码如下

            var dialog = new Microsoft.Win32.OpenFileDialog();
            dialog.Title = "选择上传的文件";
            dialog.CheckFileExists = true;
            dialog.Filter = "*.zip(压缩文件)|*.zip";
            dialog.Multiselect = false;
            if (dialog.ShowDialog() == true)
            {
                DoUploadFileAsync(dialog.FileName).ContinueWith(res => {
                    Debug.WriteLine($"responseText: {res.Result}");
                });
            }
            

            接下来实现上传文件的异步方法DoUploadFileAsync,输出返回响应的结果res.Result

            上传文件

            实现异步方法DoUploadFileAsync,使用HttpClient上传文件, 代码如下

            internal async Task DoUploadFileAsync(string filePath)
            {
                try
                {
                    var url = API_BASE_URL + "/Default.aspx?type=uploadfile";
            		//System.Net.ServicePointManager.Expect100Continue = true;
                    //System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Tls12 | System.Net.SecurityProtocolType.Tls11 | System.Net.SecurityProtocolType.Tls;
                    using (var client = new HttpClient())
                    {
                        //client.Timeout = TimeSpan.FromSeconds(10);
                        //client.DefaultRequestHeaders.Add("Referer", API_BASE_URL + "/");
            			using (var formData = new MultipartFormDataContent())
            			{
            			    using (var fileStream = new System.IO.FileStream(filePath, System.IO.FileMode.Open, System.IO.FileAccess.Read))
            			    {
            			        var fileName = System.IO.Path.GetFileName(filePath);
            			        using (var streamContent = new StreamContent(fileStream, (int)fileStream.Length))
            			        {
            			            //上传文件处理方式省略...
            			
            			            using (var response = await client.PostAsync(url, formData))
            			            {
            			                if (response.IsSuccessStatusCode)
            			                {
            			                    return await response.Content.ReadAsStringAsync();
            			                }
            			                else
            			                {
            			                    throw new Exception(">>> DoUploadFileAsync NoSuccessStatusCode");
            			                }
            			            }
            			        }
            			    }
            			}
                    }
                }
                catch(Exception ex)
                {
                    Debug.WriteLine($">>>> DoUploadFileAsync Error:{ex.Message} \nStackTrace:{ex.StackTrace}");//发生一个或多个错误。
                }
                return string.Empty;
            }
            

            上传地址若是加密传输https协议, 就要设置 System.Net.ServicePointManager.SecurityProtocol 使用安全证书

            ContentType

            在上传文件处理方式中,使用不同的文件内容类型,

            multipart/form-data

            当使用内容类型为"multipart/form-data",代码如下

            var fileContent = new ByteArrayContent(streamContent.ReadAsByteArrayAsync().Result);
            fileContent.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("multipart/form-data");
            formData.Add(fileContent, "file", fileName);
            // 如果需要添加其他表单字段,可以继续添加,注意key与value对应
            // form.Add(new StringContent("value"), "key");
            

            上传文件时,后台服务器可能响应错误消息,提示路径包含非法字符,

            大致可能是文件名有包含中文时乱码引起的,因此以上方法不适用,

            application/octet-stream

            当使用内容类型为application/octet-stream,改成如下

            streamContent.Headers.Add("Content-Type", "application/octet-stream");
            var bytes = Encoding.UTF8.GetBytes($"form-data; name=\"file\"; filename=\"{fileName}\"");
            var headerValue = ;
            foreach (var b in bytes) headerValue += (Char)b;
            streamContent.Headers.Add("Content-Disposition", headerValue);
            formData.Add(streamContent, "file", fileName);
            

            以上方法,可防止中文的文件名乱码

            报错问题

            关于上传出现报错的问题收集

            无法访问对象

            报错:无法访问已释放的对象。

            看对象名是什么,可能是“System.Net.Http.MultipartFormDataContent”,

            这是因为在调用异步时,又调用了一次,调用之前就已自动释放了被引用的对象,

            适当使用using () {} 可管理对象在不用时被释放

            未同步执行异常

            报错:System.Threading.Tasks.Task 1.GetResultCore(Boolean waitCompletionNotification)

            可能是执行以下同步代码造成的,

            var responseText = client.PostAsync(url, formData).GetAwaiter().GetResult().Content.ReadAsStringAsync().Result;
            

            试试改成async和await调用方式,保证同步执行

            建立安全通道

            报错:基础连接已经关闭: 未能为 SSL/TLS 安全通道建立信任关系。

            当请求地址API_BASE_URL是带https协议,那可能会报错安全通道信任问题的异常,

            在新建的HttpClientHandler实例设置一个事件,信任所有证书

            var hander = new HttpClientHandler();
            hander.ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => {
                // 在这里添加你的证书验证逻辑
                // 返回true来表示允许所有证书(不推荐用于生产环境)
                return true;
            };
            

            用于生产环境这会不安全,要改使用 System.Net.ServicePointManager.SecurityProtocol,

            可能还会报错, 就试试改成如下代码

            var hander = new HttpClientHandler();
            hander.AllowAutoRedirect = true;
            hander.UseCookies = true;
            hander.CookieContainer = cookies;
            hander.ClientCertificateOptions = ClientCertificateOption.Automatic;
            

            通过设置ClientCertificateOptions 使用安全认证…

            最后,将hander传给client即可

            var client = new HttpClient(hander);
            //...
            

            接收文件

            如果还没有实现接收文件, 这里就在本地服务器上实现一下, 方便测试

            后台服务器的开发语言种类繁多, 这里使用一种开发语言C#,

            写一个例子, 实现接收文件

            .Net Aspx

            例如,在Default.aspx页面里实现上传文件,再到后台处理请求接收文件,

            上传文件页面内容如下,

             	

            上传文件



            $(function () { $('input[type=file]:last').on('change', onChange); }) function onChange(e) { var btn = $('form:last'); var file = btn[0]; var data = new FormData(file); $.ajax({ url:'/Default.aspx?type=uploadfile', type: 'POST', data: data, cache: false, processData: false, contentType: false,//改变默认string类型'application/json; charset=utf-8' success: function (res) { console.log('ajax success', res); }, error: function (err) { console.error('ajax error', err) } }) }

            这里使用怀旧主流的前端框架jQuery, 它的网上免费学习文档丰富

            在后台的处理接收文件,调用方法UploadFile(),代码如下

            private string UploadFile()
            {
                if (Request.Files.Count > 0)
                {
                    var file = Request.Files[0];
                    var fileName = System.IO.Path.GetFileName(file.FileName);
                    var path = System.IO.Path.Combine(Server.MapPath("~/Uploads/"), fileName);
                    file.SaveAs(path);
                    return "ok";
                }
                return "fail";
            }
            

            写到这里为止,期待下次再见!

            【C#】使用HttpClient上传文件到网站服务器和解决出错问题

VPS购买请点击我

文章版权声明:除非注明,否则均为主机测评原创文章,转载或复制请以超链接形式并注明出处。

目录[+]