如何使用HTTP POST multipart / form-data将file upload到服务器

我正在开发Windows Phone 8应用程序。 我想通过使用带有MIMEtypesmultipart / form-data和名为“userid = SOME_ID”的string数据的HTTP POST请求通过PHP web服务上载SQLite数据库。 我不想使用像HttpClient,RestSharp或MyToolkit第三方库。 我试过下面的代码,但它不上传文件也不给我任何错误。 它在Android,PHP等工作正常,所以没有问题的Web服务。 以下是我的代码(WP8)。 它出什么问题了?

我GOOGLE了我的问题,但没有为我工作。 我没有得到具体的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(); } } } } 

我使用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(imagebytearraystring, 0, imagebytearraystring.Length), "profile_pic", "hello1.jpg"); HttpResponseMessage response = await httpClient.PostAsync("PostUrl", form); response.EnsureSuccessStatusCode(); httpClient.Dispose(); string sd = response.Content.ReadAsStringAsync().Result; 

这是我最后的工作代码。 我的Web服务需要一个文件(POST参数名称是“文件”)和一个string值(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帮助我。

这个简单的版本也适用。

 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); } 

根据需要添加额外的必需标题。

我一直在玩一些,并提出了一个简化的,更通用的解决scheme:

 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']); 

你可以使用这个类:

 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>'; } 

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

  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; } 

它适用于窗口手机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); }