- 当form标签的enctype设置为multipart/form-data浏览器都干了些什么呢?
通常我们在做向服务器提交数据的功能时都会用到表单提交,默认情况下表单的enctype属性值为application/x-www-form-urlencoded,在想服务器发送数据前,所有的字符都会进行编码(空格转换为“+”号,特殊符号转换为ASCII HEX值,如“<”会转换为“%3C”);但是当我们想要做一个的包含上传的数据提交功能时,就必须要将form标签的enctype属性设置为multipart/form-data才可以,那么此时浏览器都干了些什么,接下来我们抓取一下提交表单时的请求,如下图所示:
在请求头中我们发现Content-Type后面的值中有boundary的键后面跟着一串“不明所以”的字符,在Requset PayLoad中每一个Content-Disposition前面都有同样的字符,boundary的翻译成中文就是分界线的意思,现在意思已经很明显了吧,就是说这段“不明所以”的字符串是用来分割表单中的每个数据项的,以图中最后一个红色圈选的字符串代表本次数据表单的结尾,当服务器接受到这样的格式的请求主体信息后 ,会根据Content-Type中的boundary的值来解析对应的数据。
2.通过代码来实现form以multipart/form-data的方式来提交数据
编写代码过程中需要注意一下几点:
- 每行字符串结束后都需要以“ ”换新行,特别注意一下在文件流写入到请求主体后也要有“ ”换行;
- boundary的值不能和表单数据冲突;
- Content-Type后面的boundary值的前缀长度不能和Request PayLoad中的boundary前缀长度一样
代码如下:
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://localhost:24219/upload.ashx"); //边界标识 string boundary = "WebKitFormBoundary" + Guid.NewGuid().ToString("N"); //开始边界 string beginBoundary = "------" + boundary; //结束边界 string endBoundary = "------" + boundary + "--"; request.ContentType = "multipart/form-data; boundary=----" + boundary; request.Method = "POST"; Stream requestStream = request.GetRequestStream(); //键值对 StringBuilder keyValueParam = new StringBuilder(); keyValueParam.AppendLine(beginBoundary); keyValueParam.AppendLine("Content-Disposition: form-data; name="name""); keyValueParam.AppendLine(); keyValueParam.AppendLine("o_1bfj088gv38436s13777eo1dtn1o.jpg"); keyValueParam.AppendLine(beginBoundary); keyValueParam.AppendLine("Content-Disposition: form-data; name="chunks""); keyValueParam.AppendLine(); keyValueParam.AppendLine("5"); byte[] keyValueByte = Encoding.UTF8.GetBytes(keyValueParam.ToString()); requestStream.Write(keyValueByte, 0, keyValueByte.Length); //文件 StringBuilder fileParam = new StringBuilder(); fileParam.AppendLine(beginBoundary); fileParam.AppendLine("Content-Disposition: form-data; name="file"; filename="370x323-3.jpg""); fileParam.AppendLine("Content-Type: application/octet-stream"); fileParam.AppendLine(); byte[] fileParamBytes = Encoding.UTF8.GetBytes(fileParam.ToString()); requestStream.Write(fileParamBytes, 0, fileParamBytes.Length); byte[] fileByte = File.ReadAllBytes(@"C:UsersCSQDesktop新建文件夹370x323-2.jpg"); requestStream.Write(fileByte, 0, fileByte.Length); //结束边界 StringBuilder endParam = new StringBuilder(); endParam.AppendLine(); endParam.AppendLine(endBoundary);//结束边界 byte[] endByte = Encoding.UTF8.GetBytes(endParam.ToString()); requestStream.Write(endByte, 0, endByte.Length); HttpWebResponse response = (HttpWebResponse)request.GetResponse(); Stream responseStream = response.GetResponseStream(); StreamReader reader = new StreamReader(responseStream); string result = reader.ReadToEnd();
这是用HttpWebRequest来编写的,换做HttpClient类来编写的话就更简单了,哈哈,看代码:
HttpClient client = new HttpClient(); //multipart/form-data类型的请求内容 MultipartFormDataContent httpContents = new MultipartFormDataContent(); byte[] fileByte = File.ReadAllBytes(@"C:UsersAlanDesktop新建文件夹370x323-2.jpg"); ByteArrayContent fileContent = new ByteArrayContent(fileByte); fileContent.Headers.ContentType =new MediaTypeHeaderValue("application/octet-stream"); httpContents.Add(fileContent, "file", "370x323-2.jpg"); ByteArrayContent keyValue1 = new ByteArrayContent(Encoding.UTF8.GetBytes("o_1bfj088gv38436s13777eo1dtn1o.jpg")); httpContents.Add(keyValue1, "name"); ByteArrayContent keyValue2 = new ByteArrayContent(Encoding.UTF8.GetBytes("5")); httpContents.Add(keyValue2, "chunks"); var response = client.PostAsync("http://localhost:24219/upload.ashx", httpContents).Result; response.EnsureSuccessStatusCode();
是不是很容易啊,完结!