zoukankan      html  css  js  c++  java
  • 通过multipart/form-data标头同时传输表单和文件数据以及前后台代码

    主要参考资料:

    很详细的解释了客户端如何正确组装multipart/form-data头内容以及实体内容:https://www.cnblogs.com/kissdodog/archive/2013/04/06/3002779.html

     但是其中的代码有点问题:注意是在最后request流结束的boundary也要加上--,文章的注释中写了,但是代码没有写上;

    在这里本人写的客户端代码:

    //发送multipart-formdata
            private async void Btn_MF_Send_Click(object sender, EventArgs e)
            {
                try
                {
                    string boundary = "----------" + DateTime.Now.Ticks.ToString("x");//元素分割标记 
                    StringBuilder sb = new StringBuilder();
                    sb.Append("--" + boundary);
                    //这是第一条拼接的表单数据title:Lee
                    sb.Append("
    "); 
                    sb.Append("Content-Disposition: form-data; name="title"");//新起一行前面必须"
    "
                    sb.Append("
    ");
                    sb.Append("
    ");
                    sb.Append("Lee");//value前面必须有2个换行  "
    "
                    sb.Append("
    ");
                    sb.Append("--" + boundary);
                    //这是第二条拼接的表单数据Name:张三
                    sb.Append("
    ");
                    sb.Append("Content-Disposition: form-data; name="Name"");
                    sb.Append("
    ");
                    sb.Append("
    ");
                    sb.Append("张三");//value前面必须有2个换行  "
    "
                    sb.Append("
    ");
                    sb.Append("--" + boundary);//boundary分隔符前面只需要一个"
    "
                    //下面是文件流数据
                    sb.Append("
    ");
                    sb.Append("Content-Disposition: form-data; name="11"; filename="11.docx" + """);
                    sb.Append("
    ");
                    sb.Append("Content-Type: application/octet-stream ");
                    sb.Append("
    ");
                    sb.Append("
    ");//value前面必须有2个换行 "
    " 
                    //这一行后面开始写文件内容
    
                    HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(TB_MF_Url.Text);
                    request.ContentType = "multipart/form-data;boundary=" + boundary;//其它地方的boundary比这里在前面多--
                    request.Method = "post";
                    //文件流
                    FileStream fs = new FileStream(@"E:UpLoad11.docx", FileMode.OpenOrCreate, FileAccess.Read);
                    //post流的开始部份
                    byte[] postStartBytes = Encoding.UTF8.GetBytes(sb.ToString());
                    //post流的尾巴部份
                    byte[] postEndBytes = Encoding.UTF8.GetBytes("
    --" + boundary+"--
    ");//特别注意结尾符号也有--,否则将无法正确在服务端识别到结束符
                    //post消息主体的长度
                    request.ContentLength = postStartBytes.Length + fs.Length + postEndBytes.Length;
                    //获取请求流
                    Stream reqStream = await request.GetRequestStreamAsync();
                    //写入开始部分
                    await reqStream.WriteAsync(postStartBytes, 0, postStartBytes.Length);
                    //文件流写入的缓冲区
                    byte[] buff = new byte[checked(Math.Min(1024 * 1024 * 4, fs.Length))];
                    //写入文件流
                    int bytesRead = 0;
                    while ((bytesRead=await fs.ReadAsync(buff,0,buff.Length))!=0)
                    {
                        await reqStream.WriteAsync(buff, 0, bytesRead);
                    }
                    //写入消息主体的尾巴部分
                    await reqStream.WriteAsync(postEndBytes, 0, postEndBytes.Length);
    
                    reqStream.Close();
                    fs.Close();
                    //请求响应
                    WebResponse response = await request.GetResponseAsync();
                    Stream resStream = response.GetResponseStream();
                    StreamReader reader = new StreamReader(resStream);
                    string res = await reader.ReadToEndAsync();
    
                    TB_MF_RES.Text = res;
                    reader.Close();
                    resStream.Close();
                    response.Close();
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }           
            }
        }

    服务端:

    这里服务端可以用两种方法获取请求的消息:

    方法一(推荐):

    [HttpPost]
            [ActionName("UploadFile")]
            public string UploadFile()
            {
                //文件保存的服务器路径
                string root = "E:/UpLoad/Server/";
                if (!Directory.Exists(root))
                {
                    Directory.CreateDirectory(root);
                }
    
                HttpRequest request = System.Web.HttpContext.Current.Request;
                //保存表单数据
                Dictionary<string, string> dic = new Dictionary<string, string>();
                var formData = request.Form;
                for (int i=0;i< formData.Count;i++)
                {
                    string keyName = formData.GetKey(i);
                    dic.Add(keyName, formData.Get(keyName));
                }
                //保存文件数据
                HttpFileCollection FileCollect = request.Files;           
                if (FileCollect.Count > 0)          //如果集合的数量大于0
                {
                    foreach (string str in FileCollect)
                    {
                        HttpPostedFile File = FileCollect[str];  //用key获取单个文件对象HttpPostedFile
                        //得到文件数据流,可以进行其他转存操作
                        Stream FileStream = File.InputStream;
    
                        string AbsolutePath = root + File.FileName;
                        File.SaveAs(AbsolutePath);              //将上传的东西保存
                    }
                }
    
                string res = JsonConvert.SerializeObject(dic);
                return res;
            }

    方法二:(更高的封装)

    [HttpPost]
            public async Task<string> Post()
            {
                if (!Request.Content.IsMimeMultipartContent())
                {
                    throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
                }
                Dictionary<string, string> dic = new Dictionary<string, string>();
                //string root = HttpContext.Current.Server.MapPath("~/App_Data");//指定要将文件存入的服务器物理位置 
                string root = "E:/UpLoad/Server";
                if (!Directory.Exists(root))
                {
                    Directory.CreateDirectory(root);
                }
                var provider = new MultipartFormDataStreamProvider(root);
                try
                {
                    // Read the form data.  
                    await Request.Content.ReadAsMultipartAsync(provider);
    
                    // This illustrates how to get the file names.  
                    foreach (MultipartFileData file in provider.FileData)
                    {//接收文件  
                        Trace.WriteLine(file.Headers.ContentDisposition.FileName);//获取上传文件实际的文件名  
                        Trace.WriteLine("Server file path: " + file.LocalFileName);//获取上传文件在服务上默认的文件名  
                    }//这样做直接就将文件存到了指定目录下,只接收文件数据流可通过HttpFileCollection操作 但并不保存至服务器的目录下,由开发自行指定如何存储,比如通过服务存到图片服务器  
                    foreach (var key in provider.FormData.AllKeys)
                    {//接收FormData  
                        dic.Add(key, provider.FormData[key]);
                    }
                }
                catch(Exception ex)
                {
                    return "Failed "+ex.Message;
                    throw;
                }
                return "Success";
            }

    客户端代码:

    https://gitee.com/PapillonOfLee/httpwebrequest_post_file

    服务端代码:

    https://gitee.com/PapillonOfLee/HttpWebRequestSendFileServer

    其它参考资料:

     怎么在后台解析File和表单数据:https://www.cnblogs.com/simadi/p/5032320.html

    weiapi解析文件(左侧提示栏可以查看别的方案):https://blog.csdn.net/MDZZ666/article/details/89202548

    清楚的解释了服务端是怎么读取multipart/form-data中的内容的,包括文件和表单数据:multipart/form-data:https://www.cnblogs.com/fwyTech/articles/3431015.html

    End

  • 相关阅读:
    [Notes] 如何使用abode audition录歌
    [Tips] matlab save load
    [Tips] matlab csv格式文件读写
    [Tips] 随机数 随机序列 随机排列生成
    [Tips] csv 读写
    [record] 初入android
    HTML中表格table边框border(1px还嫌粗)的解决方案:
    CSS颜色代码大全
    ie9下面的console的bug
    js 性能优化 篇一
  • 原文地址:https://www.cnblogs.com/LeeSki/p/12403205.html
Copyright © 2011-2022 走看看