在非常多企业级应用中,我们都没法直接通过开发语言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;

            }

        }

 

利用socket模拟http的混合表单上传(在一个请求中提交表单并上传多个文件)的更多相关文章

  1. gerrit上的commit msg中关联jira单号(含gerrit的安装)

    这个问题折腾了很久,前期后后大概一个月吧,终于搞定了,查了很多资料,有的不完整,有的完全就不能用,有的没说完整,所以一定要记录下来,我的心血啊. 由于公司在用的gerrit的是正式环境中的,大家都在使 ...

  2. MVC中提交表单的4种方式

    一,MVC  HtmlHelper方法 Html.BeginForm(actionName,controllerName,method,htmlAttributes){} BeginRouteForm ...

  3. 学习日记3、投机取巧使两个表的数据同时在一个treeGrid中显示

    不多说了直接上代码, $('#List').treegrid({ url: '@Url.Action("GetList")', width: $(window).width() - ...

  4. EasyUI加zTree使用解析 easyui修改操作的表单回显方法 验证框提交表单前验证 datagrid的load方法

    带参提交一次查询,从服务器加载新数据.这是一个神奇的方法 $('#dg').datagrid('load',{ code: '01', name: 'name01' }); easyui修改操作的回显 ...

  5. Spring MVC中 提交表单报错400

    背景: 在写SpringMVC表单提交的代码的时,在最后点击提交的时候总是会出现400的错误 原因: 主要原因就是表单提交的数据和对应实体类的属性无法完全匹配 解决方案: 查看我们提交的数据是否完全和 ...

  6. Java后台防止客户端重复请求、提交表单

    前言 在Web / App项目中,有一些请求或操作会对数据产生影响(比如新增.删除.修改),针对这类请求一般都需要做一些保护,以防止用户有意或无意的重复发起这样的请求导致的数据错乱. 常见处理方案 1 ...

  7. vue中提交表单后如何清空

    只需要在提交方法里写上this.form={brand_right:0}即可.

  8. Java Web中提交表单之后跳转到WebContent目录下的子目录里的jsp文件

    最近在做一个系统,需要完成登录动能进行跳转到另一个页面.在这个项目里面,我把 jsp,css,js文件都统一放在 WebContent 目录下的一个 WebPage 里面. 按照以前的习惯,写好了 s ...

  9. mysql:把DB1中A表a字段替换为DB2中B表b字段

    UPDATE DB1.A SET a = ( SELECT b FROM DB2.B WHERE B.Id = A.id) 实例: UPDATE wordpress.`wp_posts` SET po ...

随机推荐

  1. eclipse oxygen离线安装activiti

    我用的最新版本的eclipse oxygen,结果通过help-->install new software-->add 一直报找不到,后来网上查找的离线安装,终于成功了,在这里和大家分享 ...

  2. SpringBoot学习笔记(2)----配置文件取值

    今天介绍三种配置文件手动取值的方式: springboot配置文件信息保存在application.properties中,默认可以spring.开头的进行spring进行一些常用参数的配置,但是很多 ...

  3. 洛谷P2617 Dynamic Rankings 主席树 单点修改 区间查询第 K 大

    我们将线段树套在树状数组上,查询前预处理出所有要一起移动的节点编号,并在查询过程中一起将这些节点移到左右子树上. Code: #include<cstdio> #include<cs ...

  4. 设置div内的内容不能被选中

    通过简单的css设置页面的文字无法被选定. <div class="select">我不能被选中复制</div> .select{ -webkit-user ...

  5. axios的坑

    1.axios默认发送application/json 格式 https://www.cnblogs.com/qdcnbj/p/8143155.html 资料: https://www.npmjs.c ...

  6. Node_进阶_8

    Node进阶第八天 一.复习 Node.js特点:单线程.异步I/O(非阻塞I/O).事件驱动(事件环). 适合的程序:就是没有太多的计算,I/O比较多的业务. 举例:留言本.考试系统.说说.图片裁切 ...

  7. 题解 洛谷 P3376 【【模板】网络最大流】

    本人很弱,只会Dinic.EK与Ford-Fulkerson...(正在学习ISAP...) 这里讲Dinic... Dinic:与Ford-Fulkerson和的思路相似(话说好像最大流求解都差不多 ...

  8. ie11 .pac代理脚本无法使用的问题

    参考: http://blogs.msdn.com/b/ieinternals/archive/2013/10/11/web-proxy-configuration-and-ie11-changes. ...

  9. 洛谷——P3370 【模板】字符串哈希

    题目描述 如题,给定N个字符串(第i个字符串长度为Mi,字符串内包含数字.大小写字母,大小写敏感),请求出N个字符串中共有多少个不同的字符串. 友情提醒:如果真的想好好练习哈希的话,请自觉,否则请右转 ...

  10. 如何成为一个偷懒又高效的Android开发人员

    我敢肯定你对这个标题肯定心存疑惑,但事实就是如此,这个标题完全适合Android开发人员.据我所知, Android程序员不情愿写 findViewById().点击事件监听等重复率较高的代码.那我们 ...