?????? 在非常多企业级应用中,我们都没法直接通过开发语言sdk包封装的http工具来模拟http复合表单(multipart/form-data),特别是在跨语言跨平台的编程过程中。事实上实现方案并不复杂,仅仅要你了解了http协议中复合表单的报文结构就非常easy了:
??????? httpheader
??????? ------时间戳------
??????? 表单參数1
?????? ------时间戳------
?????? 表单參数2
????? ------时间戳------
????? 文件1的描写叙述+二进制信息
???? ------时间戳------
???? 文件2的描写叙述+二进制信息
?
??? 以下我们进一步以一段c#的代实例码来演示下这个结构:
???????
??????? ///<summary>
??????? ///向server发送混合型的请求,1:成功发送,0:发送失败
??????? ///</summary>
??????? ///<param name="paranames">表单參数名数组</param>
??????? ///<param name="paravalues">參数值数组</param>
??????? ///<param name="files">文件名称数组</param>
??????? ///<param name="errmsg">报错信息</param>
??????? ///<returns></returns>
??????? public int SendRequest(string[] paranames, string[] paravalues, string[] files, ref string errmsg)
??????? {
??????????? StringBuilder http, text;
??????????? byte[] httpbyte;
??????????? byte[] textbyte = null;
??????????? long length = 0;
??????????? DateTime now = DateTime.Now;
??????????? List<byte[]> data =newList<byte[]>();
??????????? //构造时间戳
??????????? string strBoundary = "------------" + DateTime.Now.Ticks.ToString("x");
??????????? byte[] boundary = Encoding.ASCII.GetBytes("\r\n" + strBoundary +"\r\n");
??????????? length += boundary.Length;
??????????? //构造时间戳
?
??????????? //载入表单參数信息
??????????? if (paranames != null)
??????????? {
??????????????? text = new StringBuilder();
??????????????? for (int i = 0; i < paranames.Length; i++)
??????????????? {
??????????????????? text.Append("--");
??????????????????? text.Append(strBoundary);//加入时间戳
??????????????????? text.Append("\r\n");
??????????????????? text.Append("Content-Disposition: form-data; name=\"" + paranames[i] +"\"\r\n\r\n");
??????????????????? text.Append(paravalues[i]);
??????????????????? text.Append("\r\n");
??????????????? }
??????????????? string para = text.ToString();
??????????????? textbyte = Encoding.ASCII.GetBytes(para);
??????????????? length += textbyte.Length;
??????????? }
?
??????????? //载入文件信息
??????????? if (files != null)
??????????? {
??????????????? for (int i = 0; i < files.Length; i++)
??????????????? {
??????????????????? FileStream fs;
??????????????????? StringBuilder sbfile =newStringBuilder();
??????????????????? try
??????????????????? {
??????????????????????? fs = File.Open(files[i],FileMode.Open,FileAccess.Read,FileShare.Read);
??????????????????????? if (i == 0) sbfile.Append("--");//加入文件
??????????????????????? else sbfile.Append("\r\n--");
??????????????????????? sbfile.Append(strBoundary);//加入时间戳???????????????????????
??????????????????????? sbfile.Append("\r\n");
??????????????????????? sbfile.Append("Content-Disposition: form-data; name=\"");
??????????????????????? sbfile.Append("file");
??????????????????????? sbfile.Append("\"; filename=\"");
??????????????????????? sbfile.Append(Path.GetFileName(files[i]));
??????????????????????? sbfile.Append("\"");
?????????????????????? ?sbfile.Append("\r\n");
??????????????????????? sbfile.Append("Content-Type: ");
??????????????????????? sbfile.Append("application/octet-stream");
??????????????????????? sbfile.Append("\r\nContent-Length:");
??????????????????????? sbfile.Append(fs.Length.ToString());
??????????????????????? sbfile.Append("\r\n");
??????????????????????? sbfile.Append("\r\n");
??????????????????????? string temp = sbfile.ToString();
??????????????????????? byte[] bin =Encoding.UTF8.GetBytes(temp);
??????????????????????? data.Add(bin);
??????????????????????? length += bin.Length;
??????????????????????? length += fs.Length;
??????????????????????? fs.Close();
??????????????????? }
??????????????????? catch (Exception exc)
??????????????????? {
??? ????????????????????errmsg = exc.Message.ToString();
??????????????????????? return 0;
??????????????????? }
?
??????????????? }
??????????? }
?
??????????? //构造http头
??????????? http = new StringBuilder();
??????????? http.Append("POST " + ur.ToString() +" HTTP/1.1\r\n");
??????????? http.Append("Content-Type:multipart/form-data;boundary=");
??????????? http.Append(strBoundary);
??????????? http.Append("\r\n");
??????????? http.Append("Host:" + ipaddress +":" + tcpport.ToString() +"\r\n");
??????????? http.Append("Content-Length:");
??????????? http.Append(length.ToString());
??????????? http.Append("\r\n");
??????????? http.Append("Expect: 100-continue\r\n");//注明要在收到server的continue消息后才继续上传http消息体
??????????? http.Append("Connection: Keep-Alive\r\n\r\n");
??????????? string strtemp = http.ToString();
??????????? httpbyte = Encoding.ASCII.GetBytes(strtemp);
?
??????????? try
??????????? {
??????????????? soc.Send(httpbyte);"//首先发送http头????????????
????????????? ?Thread.Sleep(100);
??????????????? string check = GetResponse();
??????????????? if (check == null || !check.Contains("Continue"))//得到server确认后才继续上传
??????????????? {
??????????????????? errmsg = "client已成功发送请求,但server没有响应。";
??????????????????? return 0;
??????????????? }
??????????????? if (paranames != null)
??????????????? {
??????????????????? soc.Send(textbyte, textbyte.Length, SocketFlags.None);//发送表单參数
??????????????? }
??????????????? if (files != null)
??????????????? {//依次发送文件
??????????????????? for (int i = 0; i < data.Count; i++)
??????????????????? {
??????????????????????? int size = 0;
??????????????????????? FileStream fs =File.Open(files[i],FileMode.Open, FileAccess.Read,FileShare.Read);
??????????????????????? soc.Send(data[i], data[i].Length, SocketFlags.None);
??????????????????????? byte[] buff =newbyte[1024];
??????????????????????? size = fs.Read(buff, 0, 1024);
??????????????????????? while (size > 0)
??????????????????????? {
??????????????????????????? soc.Send(buff, size, SocketFlags.None);
??????????????????????????? size = fs.Read(buff, 0, 1024);
??????????????????????? }
??????????????????????? fs.Close();
??????????????????? }
??????????????? }
??????????????? soc.Send(boundary, boundary.Length, SocketFlags.None);
??????????????? return 1;
??????????? }
??????????? catch (Exception exc)
??????????? {
??????????????? errmsg = exc.Message.ToString();
??????????????? return 0;
??????????? }
??????? }
?