HTTP的POST请求的详细构造[实现机器提交表单含上传文件及普通文本域]
2013-04-12 10:08
876 查看
最近用C#做测试网站的服务程序,由于有些接口需要真实的测试数据。比如提交表单中的文本域和文件域,但.Net中只提供了简单的单独提交文本或文件的方法,所以只能自己构造格式为
的HTTP请求,而让我更加了解了HTTP请求的格式。
下面是在Google搜索后的一个解决方案,原链接:http://stackoverflow.com/questions/566462/upload-files-with-httpwebrequest-multipart-form-data
方法1:上传文本域及一个文件[测试成功]
I believe that you are not building the request body correctly. First, you need to include part boundary (random text) in content type header. For example,
Now format of request body will be something like
I will suggest you to use tool such as Fiddler to understand how these requests are built.
multipart/form-data
的HTTP请求,而让我更加了解了HTTP请求的格式。
下面是在Google搜索后的一个解决方案,原链接:http://stackoverflow.com/questions/566462/upload-files-with-httpwebrequest-multipart-form-data
方法1:上传文本域及一个文件[测试成功]
//发送对应表单文本域和一个文件[函数中的输出语句自己调节] public static void HttpUploadFile(string url, string file, string paramName, string contentType, NameValueCollection nvc) { Console.WriteLine(string.Format("Uploading {0} to {1}", file, url)); string boundary = "---------------------------" + DateTime.Now.Ticks.ToString("x"); byte[] boundarybytes = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\n"); HttpWebRequest wr = (HttpWebRequest)WebRequest.Create(url); wr.ContentType = "multipart/form-data; boundary=" + boundary; wr.Method = "POST"; wr.KeepAlive = true; wr.Credentials = System.Net.CredentialCache.DefaultCredentials; Stream rs = wr.GetRequestStream(); string formdataTemplate = "Content-Disposition: form-data; name=\"{0}\"\r\n\r\n{1}"; foreach (string key in nvc.Keys) { 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, file, 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); Console.WriteLine(string.Format("File uploaded, server response is: {0}", reader2.ReadToEnd())); } catch (Exception ex) { //log.Error("Error uploading file", ex); if (wresp != null) { wresp.Close(); wresp = null; } } finally { wr = null; } }
//使用的例子 //nvc中存放表单文本域的键值对 //image/jpeg是上传文件的格式 NameValueCollection nvc = new NameValueCollection(); nvc.Add("id", "TTR"); nvc.Add("btn-submit-photo", "Upload"); HttpUploadFile("http://your.server.com/upload", @"C:\test\test.jpg", "file", "image/jpeg", nvc);
方法2:上传表单文本域和多个文件[我没测试成功]
public static void UploadFilesToRemoteUrl(string url, string[] files, string logpath, NameValueCollection nvc) { long length = 0; string boundary = "----------------------------" + DateTime.Now.Ticks.ToString("x"); HttpWebRequest httpWebRequest2 = (HttpWebRequest)WebRequest.Create(url); httpWebRequest2.ContentType = "multipart/form-data; boundary=" + boundary; httpWebRequest2.Method = "POST"; httpWebRequest2.KeepAlive = true; httpWebRequest2.Credentials = System.Net.CredentialCache.DefaultCredentials; Stream memStream = new System.IO.MemoryStream(); byte[] boundarybytes = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\n"); string formdataTemplate = "\r\n--" + boundary + "\r\nContent-Disposition: form-data; name=\"{0}\";\r\n\r\n{1}"; foreach (string key in nvc.Keys) { string formitem = string.Format(formdataTemplate, key, nvc[key]); byte[] formitembytes = System.Text.Encoding.UTF8.GetBytes(formitem); memStream.Write(formitembytes, 0, formitembytes.Length); } memStream.Write(boundarybytes, 0, boundarybytes.Length); string headerTemplate = "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\n Content-Type: application/octet-stream\r\n\r\n"; for (int i = 0; i < files.Length; i++) { //string header = string.Format(headerTemplate, "file" + i, files[i]); string header = string.Format(headerTemplate, "uplTheFile", files[i]); byte[] headerbytes = System.Text.Encoding.UTF8.GetBytes(header); memStream.Write(headerbytes, 0, headerbytes.Length); FileStream fileStream = new FileStream(files[i], FileMode.Open, FileAccess.Read); byte[] buffer = new byte[1024]; int bytesRead = 0; while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0) { memStream.Write(buffer, 0, bytesRead); } memStream.Write(boundarybytes, 0, boundarybytes.Length); fileStream.Close(); } httpWebRequest2.ContentLength = memStream.Length; Stream requestStream = httpWebRequest2.GetRequestStream(); memStream.Position = 0; byte[] tempBuffer = new byte[memStream.Length]; memStream.Read(tempBuffer, 0, tempBuffer.Length); memStream.Close(); requestStream.Write(tempBuffer, 0, tempBuffer.Length); requestStream.Close(); WebResponse webResponse2 = httpWebRequest2.GetResponse(); Stream stream2 = webResponse2.GetResponseStream(); StreamReader reader2 = new StreamReader(stream2); MessageBox.Show(reader2.ReadToEnd()); webResponse2.Close(); httpWebRequest2 = null; webResponse2 = null; }
原理解释:
详细见链接。下面简单复制过来的。I believe that you are not building the request body correctly. First, you need to include part boundary (random text) in content type header. For example,
Content-Type: multipart/form-data; boundary=----WebKitFormBoundarySkAQdHysJKel8YBM
Now format of request body will be something like
------WebKitFormBoundarySkAQdHysJKel8YBM Content-Disposition: form-data;name="key" KeyValueGoesHere ------WebKitFormBoundarySkAQdHysJKel8YBM Content-Disposition: form-data;name="param2" ValueHere ------WebKitFormBoundarySkAQdHysJKel8YBM Content-Disposition: form-data;name="fileUpload"; filename="y1.jpg" Content-Type: image/jpeg [image data goes here]
I will suggest you to use tool such as Fiddler to understand how these requests are built.
相关文章推荐
- httpurlconnection模拟post提交form表单(普通文本和上传文件) (
- Multipart/form-data POST文件上传详解 理论 简单的HTTP POST 大家通过HTTP向服务器发送POST请求提交数据,都是通过form表单提交的,代码如下: <form me
- 利用socket模拟http的混合表单上传(在一个请求中提交表单并上传多个文件)
- http以post方式上传一个文件,构造其请求头和消息报文
- HTTP POST请求报文格式分析与Java实现文件上传
- HTTP POST请求报文格式分析与Java实现文件上传
- HTTP POST请求报文格式分析与Java实现文件上传
- HTTP POST请求报文格式分析与Java实现文件上传
- [转载]http以post方式上传一个文件,构造其请求头和消息报文
- Android_HttpClient_get请求post表单提交上传
- http以post方式上传一个文件,构造其请求头和消息报文 application/x-www-form-urlencoded multipart/form-data
- springmvc-普通form表单提交 4000 方式实现文件上传
- HTTP POST请求报文格式分析与Java实现文件上传
- HttpClient 4.5版本实现文件上传下载以及常用post、get请求
- http以post方式上传一个文件,构造其请求头和消息报文
- 利用socket模拟http的混合表单上传(在一个请求中提交表单并上传多个文件)
- http以post方式上传一个文件,构造其请求头和消息报文
- 使用HttpURLConnection通过POST方式提交请求数据,并上传文件
- [转载]http以post方式上传一个文件,构造其请求头和消息报文
- HttpClient 4.3.6 使用MultipartEntityBuilder实现类似form表单提交方式的文件上传