【问题标题】:How to upload file to server with HTTP POST multipart/form-data?如何使用 HTTP POST multipart/form-data 将文件上传到服务器?
【发布时间】:2013-11-26 02:01:12
【问题描述】:

我正在开发 Windows Phone 8 应用程序。我想通过 PHP Web 服务使用 MIME 类型 multipart/form-data 和一个名为“userid=SOME_ID”的字符串数据的 HTTP POST 请求上传 SQLite 数据库。

我不想使用 HttpClient、RestSharp 或 MyToolkit 等第 3 方库。我尝试了下面的代码,但它没有上传文件,也没有给我任何错误。它在 Android、PHP 等中运行良好,因此在 Web 服务中没有问题。下面是我给定的代码(用于 WP8)。有什么问题?

我已经用谷歌搜索过,但我没有具体了解 WP8

async void MainPage_Loaded(object sender, RoutedEventArgs e)
{
    var file = await Windows.ApplicationModel.Package.Current.InstalledLocation.GetFileAsync(DBNAME);
    //Below line gives me file with 0 bytes, why? Should I use 
    //IsolatedStorageFile instead of StorageFile
    //var file = await ApplicationData.Current.LocalFolder.GetFileAsync(DBNAME);
    byte[] fileBytes = null;
    using (var stream = await file.OpenReadAsync())
    {
        fileBytes = new byte[stream.Size];
        using (var reader = new DataReader(stream))
        {
            await reader.LoadAsync((uint)stream.Size);
            reader.ReadBytes(fileBytes);
        }
    }

    //var res = await HttpPost(Util.UPLOAD_BACKUP, fileBytes);
    HttpPost(fileBytes);
}

private void HttpPost(byte[] file_bytes)
{
    HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create("http://www.myserver.com/upload.php");
    httpWebRequest.ContentType = "multipart/form-data";
    httpWebRequest.Method = "POST";
    var asyncResult = httpWebRequest.BeginGetRequestStream((ar) => { GetRequestStreamCallback(ar, file_bytes); }, httpWebRequest);  
}

private void GetRequestStreamCallback(IAsyncResult asynchronousResult, byte[] postData)  
{
    //DON'T KNOW HOW TO PASS "userid=some_user_id"  
    HttpWebRequest request = (HttpWebRequest)asynchronousResult.AsyncState;  
    Stream postStream = request.EndGetRequestStream(asynchronousResult);  
    postStream.Write(postData, 0, postData.Length);  
    postStream.Close();  
    var asyncResult = request.BeginGetResponse(new AsyncCallback(GetResponseCallback), request);  
}  

private void GetResponseCallback(IAsyncResult asynchronousResult)  
{  
    HttpWebRequest request = (HttpWebRequest)asynchronousResult.AsyncState;  
    HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(asynchronousResult);  
    Stream streamResponse = response.GetResponseStream();  
    StreamReader streamRead = new StreamReader(streamResponse);  
    string responseString = streamRead.ReadToEnd();  
    streamResponse.Close();  
    streamRead.Close();  
    response.Close();  
}  

我也尝试在 Windows 8 中解决我的问题,但它也无法正常工作。

public async Task Upload(byte[] fileBytes)
{
    using (var client = new HttpClient())
    {
        using (var content = new MultipartFormDataContent("Upload----" + DateTime.Now.ToString(System.Globalization.CultureInfo.InvariantCulture)))
        {
            content.Add(new StreamContent(new MemoryStream(fileBytes)));
            //Not sure below line is true or not
            content.Add(new StringContent("userid=farhanW8"));
            using (var message = await client.PostAsync("http://www.myserver.com/upload.php", content))
            {
                var input = await message.Content.ReadAsStringAsync();
            }
        }
    }
}

【问题讨论】:

    标签: c# php post windows-phone-8 multipartform-data


    【解决方案1】:

    基于@Wolf5 的回答这对我有用

    var client = new WebClient();
    client.Encoding = Encoding.UTF8;
    var boundary = $"--------------------------{DateTime.Now.Ticks:x}";
    client.Headers.Add("Content-Type", "multipart/form-data; boundary=" + boundary);
    client.Headers.Add("Cookie", cookie); 
    
    var start = $"--{boundary}\r\nContent-Disposition: form-data; name=\"file\"; filename=\"{Path.GetFileName(fileName)}\"\r\nContent-Type: image/jpeg\r\n\r\n";
    var end = $"\r\n--{boundary}--\r\n";
    
    var lst = new List<byte>();
    lst.AddRange(client.Encoding.GetBytes(start));
    lst.AddRange(File.ReadAllBytes(fileName));
    lst.AddRange(client.Encoding.GetBytes(end));
    
    var resp = client.UploadData($"{ApiUrl}/api/upload/image", "POST", lst.ToArray());
    

    【讨论】:

      【解决方案2】:

      使用 MultipartFormDataContent 的基本实现:-

      HttpClient httpClient = new HttpClient();
      MultipartFormDataContent form = new MultipartFormDataContent();
      
      form.Add(new StringContent(username), "username");
      form.Add(new StringContent(useremail), "email");
      form.Add(new StringContent(password), "password");            
      form.Add(new ByteArrayContent(file_bytes, 0, file_bytes.Length), "profile_pic", "hello1.jpg");
      HttpResponseMessage response = await httpClient.PostAsync("PostUrl", form);
      
      response.EnsureSuccessStatusCode();
      httpClient.Dispose();
      string sd = response.Content.ReadAsStringAsync().Result;
      

      【讨论】:

      • 谢谢,我不想依赖 HttpClient,如果本机支持的话。 HttpClient 可通过 WP8 中的 NuGet 获得
      • MultipartFormDataContent 仅在 WP8.1 中可用
      • MultipartFormDataContent 在 .NET 4.5(不仅仅是 WP)中可用
      • 您可以通过流添加文件,而不是将整个文件内容作为字节[]保存在内存中。 var fileStream = new FileStream(filePath, FileMode.Open); form.Add(new StreamContent(fileStream), "profile_pic");
      • 永远不要调用新的 HttpClient。哟可以破坏你的软件aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong
      【解决方案3】:

      我知道这是一个旧线程,但我一直在努力解决这个问题,我想分享我的解决方案。

      此解决方案适用于来自System.Net.HttpHttpClientMultipartFormDataContent。您可以使用.NET Core 1.0 或更高版本或.NET Framework 4.5 或更高版本发布它。

      简单概括一下,它是一种异步方法,它接收您要执行 POST 的 URL、用于发送字符串的键/值集合和用于发送文件的键/值集合作为参数。

      private static async Task<HttpResponseMessage> Post(string url, NameValueCollection strings, NameValueCollection files)
      {
          var formContent = new MultipartFormDataContent(/* If you need a boundary, you can define it here */);
      
          // Strings
          foreach (string key in strings.Keys)
          {
              string inputName = key;
              string content = strings[key];
      
              formContent.Add(new StringContent(content), inputName);
          }
      
          // Files
          foreach (string key in files.Keys)
          {
              string inputName = key;
              string fullPathToFile = files[key];
      
              FileStream fileStream = File.OpenRead(fullPathToFile);
              var streamContent = new StreamContent(fileStream);
              var fileContent = new ByteArrayContent(streamContent.ReadAsByteArrayAsync().Result);
              formContent.Add(fileContent, inputName, Path.GetFileName(fullPathToFile));
          }
      
          var myHttpClient = new HttpClient();
          var response = await myHttpClient.PostAsync(url, formContent);
          //string stringContent = await response.Content.ReadAsStringAsync(); // If you need to read the content
      
          return response;
      }
      

      您可以像这样准备您的 POST(您可以根据需要添加很多字符串和文件):

      string url = @"http://yoursite.com/upload.php"
      
      NameValueCollection strings = new NameValueCollection();
      strings.Add("stringInputName1", "The content for input 1");
      strings.Add("stringInputNameN", "The content for input N");
      
      NameValueCollection files = new NameValueCollection();
      files.Add("fileInputName1", @"FullPathToFile1"); // Path + filename
      files.Add("fileInputNameN", @"FullPathToFileN");
      

      最后,像这样调用方法:

      var result = Post(url, strings, files).GetAwaiter().GetResult();
      

      如果你愿意,你可以检查你的状态码,并显示原因如下:

      if (result.StatusCode == HttpStatusCode.OK)
      {
          // Logic if all was OK
      }
      else
      {
          // You can show a message like this:
          Console.WriteLine(string.Format("Error. StatusCode: {0} | ReasonPhrase: {1}", result.StatusCode, result.ReasonPhrase));
      }
      

      如果有人需要,这里我举一个小例子来说明如何使用 PHP 接收存储文件(在我们的 .Net 应用程序的另一端):

      <?php
      
      if (isset($_FILES['fileInputName1']) && $_FILES['fileInputName1']['error'] === UPLOAD_ERR_OK)
      {
        $fileTmpPath = $_FILES['fileInputName1']['tmp_name'];
        $fileName = $_FILES['fileInputName1']['name'];
      
        move_uploaded_file($fileTmpPath, '/the/final/path/you/want/' . $fileName);
      }
      

      我希望你觉得它有用,我很注意你的问题。

      【讨论】:

      • Async().Result 不是异步的
      • @OwnageIsMagic 我无法理解您指的是代码的哪一部分。让我们检查一下这里发生的事情的顺序: 1) HttpClient() 对象中的 PostAsync(...),它是异步的。 2) 由于 1),我的 Post 方法返回一个异步任务。 3) 由于 2),我将 Post(...) 方法与 GetAwaiter().GetResult() 挂钩,以等待异步任务结束。我错过了什么?干杯
      • 我指的是streamContent.ReadAsByteArrayAsync().Result。但是GetAwaiter().GetResult() 也不是异步的
      【解决方案4】:

      这是带有基本身份验证 C# 的多部分数据发布

      public string UploadFilesToRemoteUrl(string url)
          {
              try
              {                             
      
                  Dictionary<string, object> formFields = new Dictionary<string, object>();
                  formFields.Add("requestid", "{\"id\":\"idvalue\"}");
      
                  string boundary = "----------------------------" + DateTime.Now.Ticks.ToString("x");
      
                  HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
                  request.ContentType = "multipart/form-data; boundary=" + boundary;
      
                  // basic authentication.
                  var username = "userid";
                  var password = "password";
      
                  string credidentials = username + ":" + password;
                  var authorization = Convert.ToBase64String(Encoding.Default.GetBytes(credidentials));
                  request.Headers["Authorization"] = "Basic " + authorization;
      
                  request.Method = "POST";
                  request.KeepAlive = true;
      
                  Stream memStream = new System.IO.MemoryStream();
                  WriteFormData(formFields, memStream, boundary);
      
                  FileInfo fileToUpload = new FileInfo(@"filelocation with name");
                  string fileFormKey = "file";
                  if (fileToUpload != null)
                  {
                      WritefileToUpload(fileToUpload, memStream, boundary, fileFormKey);
                  }
                  request.ContentLength = memStream.Length;
      
                  using (Stream requestStream = request.GetRequestStream())
                  {
                      memStream.Position = 0;
                      byte[] tempBuffer = new byte[memStream.Length];
                      memStream.Read(tempBuffer, 0, tempBuffer.Length);
                      memStream.Close();
                      requestStream.Write(tempBuffer, 0, tempBuffer.Length);
                  }
      
                  using (var response = request.GetResponse())
                  {
                      Stream responseSReam = response.GetResponseStream();
                      StreamReader streamReader = new StreamReader(responseSReam);
                      return streamReader.ReadToEnd();
                  }
              }
              catch (WebException ex)
              {
                  using (WebResponse response = ex.Response)
                  {
                      HttpWebResponse httpResponse = (HttpWebResponse)response;
                      using (var streamReader = new StreamReader(response.GetResponseStream()))
                          return streamReader.ReadToEnd();
      
                  }
              }
          }
      
          // write form id.
          public static void WriteFormData(Dictionary<string, object> dictionary, Stream stream, string mimeBoundary)
          {
              string formdataTemplate = "\r\n--" + mimeBoundary +
                                          "\r\nContent-Disposition: form-data; name=\"{0}\";\r\n\r\n{1}";
              if (dictionary != null)
              {
                  foreach (string key in dictionary.Keys)
                  {
                      string formitem = string.Format(formdataTemplate, key, dictionary[key]);
                      byte[] formitembytes = System.Text.Encoding.UTF8.GetBytes(formitem);
                      stream.Write(formitembytes, 0, formitembytes.Length);
                  }
              }
          }
      
          // write file.
          public static void WritefileToUpload(FileInfo file, Stream stream, string mimeBoundary, string formkey)
          {
              var boundarybytes = System.Text.Encoding.ASCII.GetBytes("\r\n--" + mimeBoundary + "\r\n");
              var endBoundaryBytes = System.Text.Encoding.ASCII.GetBytes("\r\n--" + mimeBoundary + "--");
      
              string headerTemplate = "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\n" +
                                      "Content-Type: application/octet-stream\r\n\r\n";
      
              stream.Write(boundarybytes, 0, boundarybytes.Length);
              var header = string.Format(headerTemplate, formkey, file.Name);
              var headerbytes = System.Text.Encoding.UTF8.GetBytes(header);
      
              stream.Write(headerbytes, 0, headerbytes.Length);
      
              using (var fileStream = new FileStream(file.FullName, FileMode.Open, FileAccess.Read))
              {
                  var buffer = new byte[1024];
                  var bytesRead = 0;
                  while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
                  {
                      stream.Write(buffer, 0, bytesRead);
                  }
              }
              stream.Write(endBoundaryBytes, 0, endBoundaryBytes.Length);
          } 
      

      【讨论】:

        【解决方案5】:

        以下是在将文件作为多格式数据发送时对我有用的方法:

            public T HttpPostMultiPartFileStream<T>(string requestURL, string filePath, string fileName)
            {
                string content = null;
        
                using (MultipartFormDataContent form = new MultipartFormDataContent())
                {
                    StreamContent streamContent;
                    using (var fileStream = new FileStream(filePath, FileMode.Open))
                    {
                        streamContent = new StreamContent(fileStream);
        
                        streamContent.Headers.Add("Content-Type", "application/octet-stream");
                        streamContent.Headers.Add("Content-Disposition", string.Format("form-data; name=\"file\"; filename=\"{0}\"", fileName));
                        form.Add(streamContent, "file", fileName);
        
                        using (HttpClient client = GetAuthenticatedHttpClient())
                        {
                            HttpResponseMessage response = client.PostAsync(requestURL, form).GetAwaiter().GetResult();
                            content = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();
        
        
        
                            try
                            {
                                return JsonConvert.DeserializeObject<T>(content);
                            }
                            catch (Exception ex)
                            {
                                // Log the exception
                            }
        
                            return default(T);
                        }
                    }
                }
            }
        

        上面使用的GetAuthenticatedHttpClient可以是:

        private HttpClient GetAuthenticatedHttpClient()
        {
            HttpClient httpClient = new HttpClient();
            httpClient.BaseAddress = new Uri(<yourBaseURL>));
            httpClient.DefaultRequestHeaders.Add("Token, <yourToken>);
            return httpClient;
        }
        

        【讨论】:

        • 感谢MultipartFormDataContent 的想法,这正是我想要的。
        【解决方案6】:

        置顶到@loop 答案。

        我们得到以下 Asp.Net MVC 错误, 无法连接到远程服务器

        修复: 在 Web.Confing 中添加以下代码后,问题已为我们解决

          <system.net>
            <defaultProxy useDefaultCredentials="true" >
            </defaultProxy>
          </system.net>
        

        【讨论】:

          【解决方案7】:

          大家好,经过一天的网络搜索,我终于用下面的源代码解决了问题 希望能帮到你

              public UploadResult UploadFile(string  fileAddress)
              {
                  HttpClient client = new HttpClient();
          
                  MultipartFormDataContent form = new MultipartFormDataContent();
                  HttpContent content = new StringContent("fileToUpload");
                  form.Add(content, "fileToUpload");       
                  var stream = new FileStream(fileAddress, FileMode.Open);            
                  content = new StreamContent(stream);
                  var fileName = 
                  content.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
                  {
                      Name = "name",
                      FileName = Path.GetFileName(fileAddress),                 
                  };
                  form.Add(content);
                  HttpResponseMessage response = null;          
          
                  var url = new Uri("http://192.168.10.236:2000/api/Upload2");
                  response = (client.PostAsync(url, form)).Result;          
          
              }
          

          【讨论】:

            【解决方案8】:

            我还想将内容上传到服务器,这是一个 Spring 应用程序,我终于发现我需要为它设置一个内容类型才能将其解释为文件。就像这样:

            ...
            MultipartFormDataContent form = new MultipartFormDataContent();
            var fileStream = new FileStream(uniqueTempPathInProject, FileMode.Open);
            var streamContent = new StreamContent(fileStream);
            streamContent.Headers.ContentType=new MediaTypeHeaderValue("application/zip");
            form.Add(streamContent, "file",fileName);
            ...
            

            【讨论】:

            • 这是我看到的最干净的解决方案。您可以做的唯一改进是在前三行中的每一行前面添加“使用”。
            【解决方案9】:

            对于在尝试以多部分形式上传时搜索 403 禁止问题的人,以下可能会有所帮助,因为根据服务器配置,由于 MultipartFormDataContent 标头不正确,您将获得 MULTIPART_STRICT_ERROR "!@eq 0" 的情况。 请注意,imagetag/filename 变量都包含引号 (\") 例如 filename="\"myfile.png\"" .

                MultipartFormDataContent form = new MultipartFormDataContent();
                ByteArrayContent imageContent = new ByteArrayContent(fileBytes, 0, fileBytes.Length);
                imageContent.Headers.TryAddWithoutValidation("Content-Disposition", "form-data; name="+imagetag+"; filename="+filename);
                imageContent.Headers.TryAddWithoutValidation("Content-Type", "image / png");
                form.Add(imageContent, imagetag, filename);
            

            【讨论】:

              【解决方案10】:

              以下代码读取文件,将其转换为字节数组,然后向服务器发出请求。

                  public void PostImage()
                  {
                      HttpClient httpClient = new HttpClient();
                      MultipartFormDataContent form = new MultipartFormDataContent();
              
                      byte[] imagebytearraystring = ImageFileToByteArray(@"C:\Users\Downloads\icon.png");
                      form.Add(new ByteArrayContent(imagebytearraystring, 0, imagebytearraystring.Count()), "profile_pic", "hello1.jpg");
                      HttpResponseMessage response = httpClient.PostAsync("your url", form).Result;
              
                      httpClient.Dispose();
                      string sd = response.Content.ReadAsStringAsync().Result;
                  }
              
                  private byte[] ImageFileToByteArray(string fullFilePath)
                  {
                      FileStream fs = File.OpenRead(fullFilePath);
                      byte[] bytes = new byte[fs.Length];
                      fs.Read(bytes, 0, Convert.ToInt32(fs.Length));
                      fs.Close();
                      return bytes;
                  }
              

              【讨论】:

                【解决方案11】:

                这是我的最终工作代码。我的网络服务需要一个文件(POST 参数名称为“file”)和一个字符串值(POST 参数名称为“userid”)。

                /// <summary>
                /// Occurs when upload backup application bar button is clicked. Author : Farhan Ghumra
                 /// </summary>
                private async void btnUploadBackup_Click(object sender, EventArgs e)
                {
                    var dbFile = await ApplicationData.Current.LocalFolder.GetFileAsync(Util.DBNAME);
                    var fileBytes = await GetBytesAsync(dbFile);
                    var Params = new Dictionary<string, string> { { "userid", "9" } };
                    UploadFilesToServer(new Uri(Util.UPLOAD_BACKUP), Params, Path.GetFileName(dbFile.Path), "application/octet-stream", fileBytes);
                }
                
                /// <summary>
                /// Creates HTTP POST request & uploads database to server. Author : Farhan Ghumra
                /// </summary>
                private void UploadFilesToServer(Uri uri, Dictionary<string, string> data, string fileName, string fileContentType, byte[] fileData)
                {
                    string boundary = "----------" + DateTime.Now.Ticks.ToString("x");
                    HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(uri);
                    httpWebRequest.ContentType = "multipart/form-data; boundary=" + boundary;
                    httpWebRequest.Method = "POST";
                    httpWebRequest.BeginGetRequestStream((result) =>
                    {
                        try
                        {
                            HttpWebRequest request = (HttpWebRequest)result.AsyncState;
                            using (Stream requestStream = request.EndGetRequestStream(result))
                            {
                                WriteMultipartForm(requestStream, boundary, data, fileName, fileContentType, fileData);
                            }
                            request.BeginGetResponse(a =>
                            {
                                try
                                {
                                    var response = request.EndGetResponse(a);
                                    var responseStream = response.GetResponseStream();
                                    using (var sr = new StreamReader(responseStream))
                                    {
                                        using (StreamReader streamReader = new StreamReader(response.GetResponseStream()))
                                        {
                                            string responseString = streamReader.ReadToEnd();
                                            //responseString is depend upon your web service.
                                            if (responseString == "Success")
                                            {
                                                MessageBox.Show("Backup stored successfully on server.");
                                            }
                                            else
                                            {
                                                MessageBox.Show("Error occurred while uploading backup on server.");
                                            } 
                                        }
                                    }
                                }
                                catch (Exception)
                                {
                
                                }
                            }, null);
                        }
                        catch (Exception)
                        {
                
                        }
                    }, httpWebRequest);
                }
                
                /// <summary>
                /// Writes multi part HTTP POST request. Author : Farhan Ghumra
                /// </summary>
                private void WriteMultipartForm(Stream s, string boundary, Dictionary<string, string> data, string fileName, string fileContentType, byte[] fileData)
                {
                    /// The first boundary
                    byte[] boundarybytes = Encoding.UTF8.GetBytes("--" + boundary + "\r\n");
                    /// the last boundary.
                    byte[] trailer = Encoding.UTF8.GetBytes("\r\n--" + boundary + "--\r\n");
                    /// the form data, properly formatted
                    string formdataTemplate = "Content-Dis-data; name=\"{0}\"\r\n\r\n{1}";
                    /// the form-data file upload, properly formatted
                    string fileheaderTemplate = "Content-Dis-data; name=\"{0}\"; filename=\"{1}\";\r\nContent-Type: {2}\r\n\r\n";
                
                    /// Added to track if we need a CRLF or not.
                    bool bNeedsCRLF = false;
                
                    if (data != null)
                    {
                        foreach (string key in data.Keys)
                        {
                            /// if we need to drop a CRLF, do that.
                            if (bNeedsCRLF)
                                WriteToStream(s, "\r\n");
                
                            /// Write the boundary.
                            WriteToStream(s, boundarybytes);
                
                            /// Write the key.
                            WriteToStream(s, string.Format(formdataTemplate, key, data[key]));
                            bNeedsCRLF = true;
                        }
                    }
                
                    /// If we don't have keys, we don't need a crlf.
                    if (bNeedsCRLF)
                        WriteToStream(s, "\r\n");
                
                    WriteToStream(s, boundarybytes);
                    WriteToStream(s, string.Format(fileheaderTemplate, "file", fileName, fileContentType));
                    /// Write the file data to the stream.
                    WriteToStream(s, fileData);
                    WriteToStream(s, trailer);
                }
                
                /// <summary>
                /// Writes string to stream. Author : Farhan Ghumra
                /// </summary>
                private void WriteToStream(Stream s, string txt)
                {
                    byte[] bytes = Encoding.UTF8.GetBytes(txt);
                    s.Write(bytes, 0, bytes.Length);
                }
                
                /// <summary>
                /// Writes byte array to stream. Author : Farhan Ghumra
                /// </summary>
                private void WriteToStream(Stream s, byte[] bytes)
                {
                    s.Write(bytes, 0, bytes.Length);
                }
                
                /// <summary>
                /// Returns byte array from StorageFile. Author : Farhan Ghumra
                /// </summary>
                private async Task<byte[]> GetBytesAsync(StorageFile file)
                {
                    byte[] fileBytes = null;
                    using (var stream = await file.OpenReadAsync())
                    {
                        fileBytes = new byte[stream.Size];
                        using (var reader = new DataReader(stream))
                        {
                            await reader.LoadAsync((uint)stream.Size);
                            reader.ReadBytes(fileBytes);
                        }
                    }
                
                    return fileBytes;
                }
                

                非常感谢Darin Rousseau 的帮助。

                【讨论】:

                  【解决方案12】:

                  它适用于window phone 8.1。你可以试试这个。

                  Dictionary<string, object> _headerContents = new Dictionary<string, object>();
                  const String _lineEnd = "\r\n";
                  const String _twoHyphens = "--";
                  const String _boundary = "*****";
                  private async void UploadFile_OnTap(object sender, System.Windows.Input.GestureEventArgs e)
                  {
                     Uri serverUri = new Uri("http:www.myserver.com/Mp4UploadHandler", UriKind.Absolute);    
                     string fileContentType = "multipart/form-data";       
                     byte[] _boundarybytes = Encoding.UTF8.GetBytes(_twoHyphens + _boundary + _lineEnd);
                     byte[] _trailerbytes = Encoding.UTF8.GetBytes(_twoHyphens + _boundary + _twoHyphens + _lineEnd);
                     Dictionary<string, object> _headerContents = new Dictionary<string, object>();
                     SetEndHeaders();  // to add some extra parameter if you need
                  
                     httpWebRequest = (HttpWebRequest)WebRequest.Create(serverUri);
                     httpWebRequest.ContentType = fileContentType + "; boundary=" + _boundary;
                     httpWebRequest.Method = "POST";
                     httpWebRequest.AllowWriteStreamBuffering = false;  // get response after upload header part
                  
                     var fileName = Path.GetFileName(MediaStorageFile.Path);    
                     Stream fStream = (await MediaStorageFile.OpenAsync(Windows.Storage.FileAccessMode.Read)).AsStream(); //MediaStorageFile is a storage file from where you want to upload the file of your device    
                     string fileheaderTemplate = "Content-Disposition: form-data; name=\"{0}\"" + _lineEnd + _lineEnd + "{1}" + _lineEnd;    
                     long httpLength = 0;
                     foreach (var headerContent in _headerContents) // get the length of upload strem
                     httpLength += _boundarybytes.Length + Encoding.UTF8.GetBytes(string.Format(fileheaderTemplate, headerContent.Key, headerContent.Value)).Length;
                  
                     httpLength += _boundarybytes.Length + Encoding.UTF8.GetBytes("Content-Disposition: form-data; name=\"uploadedFile\";filename=\"" + fileName + "\"" + _lineEnd).Length
                                                         + Encoding.UTF8.GetBytes(_lineEnd).Length * 2 + _trailerbytes.Length;
                     httpWebRequest.ContentLength = httpLength + fStream.Length;  // wait until you upload your total stream 
                  
                      httpWebRequest.BeginGetRequestStream((result) =>
                      {
                         try
                         {
                           HttpWebRequest request = (HttpWebRequest)result.AsyncState;
                           using (Stream stream = request.EndGetRequestStream(result))
                           {
                              foreach (var headerContent in _headerContents)
                              {
                                 WriteToStream(stream, _boundarybytes);
                                 WriteToStream(stream, string.Format(fileheaderTemplate, headerContent.Key, headerContent.Value));
                               }
                  
                               WriteToStream(stream, _boundarybytes);
                               WriteToStream(stream, "Content-Disposition: form-data; name=\"uploadedFile\";filename=\"" + fileName + "\"" + _lineEnd);
                               WriteToStream(stream, _lineEnd);
                  
                               int bytesRead = 0;
                               byte[] buffer = new byte[2048];  //upload 2K each time
                  
                               while ((bytesRead = fStream.Read(buffer, 0, buffer.Length)) != 0)
                               {
                                 stream.Write(buffer, 0, bytesRead);
                                 Array.Clear(buffer, 0, 2048); // Clear the array.
                                }
                  
                                WriteToStream(stream, _lineEnd);
                                WriteToStream(stream, _trailerbytes);
                                fStream.Close();
                           }
                           request.BeginGetResponse(a =>
                           { //get response here
                              try
                              {
                                 var response = request.EndGetResponse(a);
                                 using (Stream streamResponse = response.GetResponseStream())
                                 using (var memoryStream = new MemoryStream())
                                 {   
                                     streamResponse.CopyTo(memoryStream);
                                     responseBytes = memoryStream.ToArray();  // here I get byte response from server. you can change depends on server response
                                 }    
                                if (responseBytes.Length > 0 && responseBytes[0] == 1)
                                   MessageBox.Show("Uploading Completed");
                                else
                                    MessageBox.Show("Uploading failed, please try again.");
                              }
                              catch (Exception ex)
                              {}
                            }, null);
                        }
                        catch (Exception ex)
                        {
                           fStream.Close();                             
                        }
                     }, httpWebRequest);
                  }
                  
                  private static void WriteToStream(Stream s, string txt)
                  {
                     byte[] bytes = Encoding.UTF8.GetBytes(txt);
                     s.Write(bytes, 0, bytes.Length);
                   }
                  
                   private static void WriteToStream(Stream s, byte[] bytes)
                   {
                     s.Write(bytes, 0, bytes.Length);
                   }
                  
                   private void SetEndHeaders()
                   {
                     _headerContents.Add("sId", LocalData.currentUser.SessionId);
                     _headerContents.Add("uId", LocalData.currentUser.UserIdentity);
                     _headerContents.Add("authServer", LocalData.currentUser.AuthServerIP);
                     _headerContents.Add("comPort", LocalData.currentUser.ComPort);
                   }
                  

                  【讨论】:

                    【解决方案13】:

                    这个简单的版本也可以。

                    public void UploadMultipart(byte[] file, string filename, string contentType, string url)
                    {
                        var webClient = new WebClient();
                        string boundary = "------------------------" + DateTime.Now.Ticks.ToString("x");
                        webClient.Headers.Add("Content-Type", "multipart/form-data; boundary=" + boundary);
                        var fileData = webClient.Encoding.GetString(file);
                        var package = string.Format("--{0}\r\nContent-Disposition: form-data; name=\"file\"; filename=\"{1}\"\r\nContent-Type: {2}\r\n\r\n{3}\r\n--{0}--\r\n", boundary, filename, contentType, fileData);
                    
                        var nfile = webClient.Encoding.GetBytes(package);
                    
                        byte[] resp = webClient.UploadData(url, "POST", nfile);
                    }
                    

                    如果需要,添加任何额外的必需标头。

                    【讨论】:

                    • 如何在Windows phone 8.1 Rt中执行?
                    • 谢谢你,狼!这对我很有帮助。
                    • 在与MultipartFormDataContent 搏斗失败后,这种方法效果很好。它不那么迷人,但如果您需要对 HTTP 消息进行详细控制,这是一个很好的解决方案。
                    • 数以百万计的感谢你,伙计,我花了 3 天时间解决了这个问题,而不是运气。Thiis 是完美的解决方案。
                    • @wolf5 在上面的例子中输入什么内容我正在尝试发送 jpg 图片
                    【解决方案14】:

                    我玩了一会儿,想出了一个简化的、更通用的解决方案:

                    private static string sendHttpRequest(string url, NameValueCollection values, NameValueCollection files = null)
                    {
                        string boundary = "----------------------------" + DateTime.Now.Ticks.ToString("x");
                        // The first boundary
                        byte[] boundaryBytes = System.Text.Encoding.UTF8.GetBytes("\r\n--" + boundary + "\r\n");
                        // The last boundary
                        byte[] trailer = System.Text.Encoding.UTF8.GetBytes("\r\n--" + boundary + "--\r\n");
                        // The first time it itereates, we need to make sure it doesn't put too many new paragraphs down or it completely messes up poor webbrick
                        byte[] boundaryBytesF = System.Text.Encoding.ASCII.GetBytes("--" + boundary + "\r\n");
                    
                        // Create the request and set parameters
                        HttpWebRequest request = (HttpWebRequest) WebRequest.Create(url);
                        request.ContentType = "multipart/form-data; boundary=" + boundary;
                        request.Method = "POST";
                        request.KeepAlive = true;
                        request.Credentials = System.Net.CredentialCache.DefaultCredentials;
                    
                        // Get request stream
                        Stream requestStream = request.GetRequestStream();
                    
                        foreach (string key in values.Keys)
                        {
                            // Write item to stream
                            byte[] formItemBytes = System.Text.Encoding.UTF8.GetBytes(string.Format("Content-Disposition: form-data; name=\"{0}\";\r\n\r\n{1}", key, values[key]));
                            requestStream.Write(boundaryBytes, 0, boundaryBytes.Length);
                            requestStream.Write(formItemBytes, 0, formItemBytes.Length);
                        }
                    
                        if (files != null)
                        { 
                            foreach(string key in files.Keys)
                            {
                                if(File.Exists(files[key]))
                                {
                                    int bytesRead = 0;
                                    byte[] buffer = new byte[2048];
                                    byte[] formItemBytes = System.Text.Encoding.UTF8.GetBytes(string.Format("Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\nContent-Type: application/octet-stream\r\n\r\n", key, files[key]));
                                    requestStream.Write(boundaryBytes, 0, boundaryBytes.Length);
                                    requestStream.Write(formItemBytes, 0, formItemBytes.Length);
                    
                                    using (FileStream fileStream = new FileStream(files[key], FileMode.Open, FileAccess.Read))
                                    {
                                        while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
                                        {
                                            // Write file content to stream, byte by byte
                                            requestStream.Write(buffer, 0, bytesRead);
                                        }
                    
                                        fileStream.Close();
                                    }
                                }
                            }
                        }
                    
                        // Write trailer and close stream
                        requestStream.Write(trailer, 0, trailer.Length);
                        requestStream.Close();
                    
                        using (StreamReader reader = new StreamReader(request.GetResponse().GetResponseStream()))
                        {
                            return reader.ReadToEnd();
                        };
                    }
                    

                    你可以这样使用它:

                    string fileLocation = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + Path.DirectorySeparatorChar + "somefile.jpg";
                    NameValueCollection values = new NameValueCollection();
                    NameValueCollection files = new NameValueCollection();
                    values.Add("firstName", "Alan");
                    files.Add("profilePicture", fileLocation);
                    sendHttpRequest("http://example.com/handler.php", values, files);
                    

                    在 PHP 脚本中,您可以像这样处理数据:

                    echo $_POST['firstName'];
                    $name = $_POST['firstName'];
                    $image = $_FILES['profilePicture'];
                    $ds = DIRECTORY_SEPARATOR;
                    move_uploaded_file($image['tmp_name'], realpath(dirname(__FILE__)) . $ds . "uploads" . $ds . $image['name']);
                    

                    【讨论】:

                    • 一次将文件一个块写入流的好工作,而不是将其全部加载到一个字节[]中并传递它。
                    【解决方案15】:

                    你可以使用这个类:

                    using System.Collections.Specialized;
                    class Post_File
                    {
                        public static void HttpUploadFile(string url, string file, string paramName, string contentType, NameValueCollection nvc)
                        {
                            string boundary = "---------------------------" + DateTime.Now.Ticks.ToString("x");
                            byte[] boundarybytes = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\n");
                            byte[] boundarybytesF = System.Text.Encoding.ASCII.GetBytes("--" + boundary + "\r\n");  // the first time it itereates, you need to make sure it doesn't put too many new paragraphs down or it completely messes up poor webbrick.  
                    
                    
                            HttpWebRequest wr = (HttpWebRequest)WebRequest.Create(url);
                            wr.Method = "POST";
                            wr.KeepAlive = true;
                            wr.Credentials = System.Net.CredentialCache.DefaultCredentials;
                            wr.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
                            var nvc2 = new NameValueCollection();
                            nvc2.Add("Accepts-Language", "en-us,en;q=0.5");
                            wr.Headers.Add(nvc2);
                            wr.ContentType = "multipart/form-data; boundary=" + boundary;
                    
                    
                            Stream rs = wr.GetRequestStream();
                    
                            bool firstLoop = true;
                            string formdataTemplate = "Content-Disposition: form-data; name=\"{0}\"\r\n\r\n{1}";
                            foreach (string key in nvc.Keys)
                            {
                                if (firstLoop)
                                {
                                    rs.Write(boundarybytesF, 0, boundarybytesF.Length);
                                    firstLoop = false;
                                }
                                else
                                {
                                    rs.Write(boundarybytes, 0, boundarybytes.Length);
                                }
                                string formitem = string.Format(formdataTemplate, key, nvc[key]);
                                byte[] formitembytes = System.Text.Encoding.UTF8.GetBytes(formitem);
                                rs.Write(formitembytes, 0, formitembytes.Length);
                            }
                            rs.Write(boundarybytes, 0, boundarybytes.Length);
                    
                            string headerTemplate = "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\nContent-Type: {2}\r\n\r\n";
                            string header = string.Format(headerTemplate, paramName, new FileInfo(file).Name, contentType);
                            byte[] headerbytes = System.Text.Encoding.UTF8.GetBytes(header);
                            rs.Write(headerbytes, 0, headerbytes.Length);
                    
                            FileStream fileStream = new FileStream(file, FileMode.Open, FileAccess.Read);
                            byte[] buffer = new byte[4096];
                            int bytesRead = 0;
                            while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
                            {
                                rs.Write(buffer, 0, bytesRead);
                            }
                            fileStream.Close();
                    
                            byte[] trailer = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "--\r\n");
                            rs.Write(trailer, 0, trailer.Length);
                            rs.Close();
                    
                            WebResponse wresp = null;
                            try
                            {
                                wresp = wr.GetResponse();
                                Stream stream2 = wresp.GetResponseStream();
                                StreamReader reader2 = new StreamReader(stream2);
                            }
                            catch (Exception ex)
                            {
                                if (wresp != null)
                                {
                                    wresp.Close();
                                    wresp = null;
                                }
                            }
                            finally
                            {
                                wr = null;
                            }
                        }
                    }
                    

                    使用它:

                    NameValueCollection nvc = new NameValueCollection();
                    //nvc.Add("id", "TTR");
                    nvc.Add("table_name", "uploadfile");
                    nvc.Add("commit", "uploadfile");
                    Post_File.HttpUploadFile("http://example/upload_file.php", @"C:\user\yourfile.docx", "uploadfile", "application/vnd.ms-excel", nvc);
                    

                    示例服务器upload_file.php:

                    m('File upload '.(@copy($_FILES['uploadfile']['tmp_name'],getcwd().'\\'.'/'.$_FILES['uploadfile']['name']) ? 'success' : 'failed'));
                    function m($msg) {
                        echo '<div style="background:#f1f1f1;border:1px solid #ddd;padding:15px;font:14px;text-align:center;font-weight:bold;">';
                        echo $msg;
                        echo '</div>';
                    }
                    

                    【讨论】:

                    • 非常好,你的代码就像一个魅力。 =) 这正是我正在寻找的普通表单字段和文件字段的解决方案。您的代码也很容易扩展以进行多文件上传。谢谢!
                    • 如果nvc为空,我相信你在开头发送了“太多新段落”(“\r\n”)。
                    猜你喜欢
                    • 2014-02-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2014-02-20
                    • 1970-01-01
                    • 1970-01-01
                    • 2017-11-16
                    • 2017-04-04
                    • 1970-01-01
                    相关资源
                    最近更新 更多