如何使用HTTP POST multipart / form-data将文件上传到服务器?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何使用HTTP POST multipart / form-data将文件上传到服务器?相关的知识,希望对你有一定的参考价值。

我正在开发Windows Phone 8应用程序。我想通过php Web服务使用MIME类型multipart / form-data和名为“userid = SOME_ID”的字符串数据的HTTP POST请求上传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(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;
另一答案

我还想把东西上传到服务器,它是一个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);
...
另一答案

这是我最后的工作代码。我的Web服务需要一个文件(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 + "
");
    /// the last boundary.
    byte[] trailer = Encoding.UTF8.GetBytes("
--" + boundary + "--
");
    /// the form data, properly formatted
    string formdataTemplate = "Content-Dis-data; name="{0}"

{1}";
    /// the form-data file upload, properly formatted
    string fileheaderTemplate = "Content-Dis-data; name="{0}"; filename="{1}";
Content-Type: {2}

";

    /// 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, "
");

            /// 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, "
");

    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}
Content-Disposition: form-data; name="file"; filename="{1}"
Content-Type: {2}

{3}
--{0}--
", boundary, filename, contentType, fileData);

    var nfile = webClient.Encoding.GetBytes(package);

    byte[] resp = webClient.UploadData(url, "POST", nfile);
}

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

另一答案

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

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("
--" + boundary + "
");
    // The last boundary
    byte[] trailer = System.Text.En

以上是关于如何使用HTTP POST multipart / form-data将文件上传到服务器?的主要内容,如果未能解决你的问题,请参考以下文章

如何通过HttpClient去POST一个multipart/form-data数据

PyQt5 和 Django:如何使用 HTTP 请求(Multipart-form)上传图像?

使用 RestSharp 发送 HTTP POST Multipart/form-data 字段

如何在 axios 中为 POST - multipart/form-data 设置 MIME 类型?

IONIC HTTP post multipart/form-data - 图像与 JSON 一起上传

如何用nodejs通过post发送multipart/form-data类型的http请求