在很多企业级应用中,我们都没法直接通过开发语言sdk包封装的http工具来模拟http复合表单(multipart/form-data),特别是在跨语言跨平台的编程过程中,其实实现方案并不复杂,只要你了解了http协议中复合表单的报文结构就很简单了:
httpheader
------时间戳------
表单参数1
------时间戳------
表单参数2
------时间戳------
文件1的描述+二进制信息
------时间戳------
文件2的描述+二进制信息
下面我们进一步以一段c#的代实例码来演示下这个结构:
///<summary>
///向服务器发送混合型的请求,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 =new list<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]);
}
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 =new stringbuilder();
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());
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("expect: 100-continue\r\n");//注明要在收到服务器的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"))//得到服务器确认后才继续上传
errmsg = "客户端已成功发送请求,但服务器没有响应!";
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 =new byte[1024];
size = fs.read(buff, 0, 1024);
while (size > 0)
{
soc.send(buff, size, socketflags.none);
size = fs.read(buff, 0, 1024);
}
soc.send(boundary, boundary.length, socketflags.none);
return 1;
catch (exception exc)
errmsg = exc.message.tostring();
return 0;
}