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

简介:

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

                    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 =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());

                        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");//注明要在收到服务器的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);

                        }

                        fs.Close();

                    }

                }

                soc.Send(boundary, boundary.Length, SocketFlags.None);

                return 1;

            }

            catch (Exception exc)

            {

                errmsg = exc.Message.ToString();

                return 0;

            }

        }


目录
相关文章
|
1天前
|
XML 前端开发 JavaScript
JavaEE:http请求 | 过滤器 | 同步与异步请求 | 跨域问题 | axios框架 有这一篇就够!
JavaEE:http请求 | 过滤器 | 同步与异步请求 | 跨域问题 | axios框架 有这一篇就够!
|
2天前
|
JavaScript
vue : 无法加载文件 D:\module\npm_module\npm_modules\vue.ps1,因为在此系统上禁止运行脚本。有关详细信息,请参阅 https:/go.microsoft.c
vue : 无法加载文件 D:\module\npm_module\npm_modules\vue.ps1,因为在此系统上禁止运行脚本。有关详细信息,请参阅 https:/go.microsoft.c
|
3天前
|
安全 Java API
深入探索 org.springframework.http.server.reactive.ServerHttpRequest:Reactive世界中的HTTP请求处理
深入探索 org.springframework.http.server.reactive.ServerHttpRequest:Reactive世界中的HTTP请求处理
10 0
|
4天前
|
Java API Spring
Spring Boot中使用Feign进行HTTP请求
Spring Boot中使用Feign进行HTTP请求
|
4天前
|
缓存 负载均衡 NoSQL
Redis系列学习文章分享---第十四篇(Redis多级缓存--封装Http请求+向tomcat发送http请求+根据商品id对tomcat集群负载均衡)
Redis系列学习文章分享---第十四篇(Redis多级缓存--封装Http请求+向tomcat发送http请求+根据商品id对tomcat集群负载均衡)
11 1
|
4天前
|
Java API Spring
Spring Boot中使用Feign进行HTTP请求
Spring Boot中使用Feign进行HTTP请求
|
4天前
|
运维 Serverless 数据处理
函数计算产品使用问题之如何通过HTTP请求进行调用
函数计算产品作为一种事件驱动的全托管计算服务,让用户能够专注于业务逻辑的编写,而无需关心底层服务器的管理与运维。你可以有效地利用函数计算产品来支撑各类应用场景,从简单的数据处理到复杂的业务逻辑,实现快速、高效、低成本的云上部署与运维。以下是一些关于使用函数计算产品的合集和要点,帮助你更好地理解和应用这一服务。
|
6天前
|
移动开发 JSON 应用服务中间件
一文搞懂:【12.5】asyncio模拟http请求
一文搞懂:【12.5】asyncio模拟http请求
11 0
|
.NET 开发框架
HTTP 错误 404 - 文件或目录未找到的最终解决方法
问题描述:       http错误404-文件或目录未找到   问题原因:         我遇到的情况是,先按装了.NET,后装的IIS;不确定其他原因也会不会产生类似错误。(如果有,希望大家能贴出更多的原因,方便遇到同样错误的人找到问题的根源)   解决方法:        ...
1647 0
|
4天前
|
数据安全/隐私保护
数据防护之=HTTPS协议增加了<数据加密>
数据防护之=HTTPS协议增加了<数据加密>