C#如何自定义multipart/form-data的解析器
更新时间:2022年06月09日 09:30:51 作者:张云勇
这篇文章主要介绍了C#如何自定义multipart/form-data的解析器,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
脚本之家 / 编程助手:解决程序员“几乎”所有问题!
脚本之家官方知识库 → 点击立即使用
使用WebSocketSharp自定义实现Web服务时,无法解析multipart/form-data请求的数据。
通过查找资料,采用以下方式实现multipart/form-data的解析器。
解析辅助类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 | using System; using System.Collections.Generic; using System.IO; using System.Text; using System.Text.RegularExpressions; namespace YongFrame.Common.Utils { /// <summary> /// multipart/form-data的解析器 /// </summary> internal class HttpMultipartParser { /// <summary> /// 参数集合 /// </summary> public IDictionary< string , string > Parameters = new Dictionary< string , string >(); /// <summary> /// 上传文件部分参数 /// </summary> public string FilePartName { get ; } /// <summary> /// 是否解析成功 /// </summary> public bool Success { get ; private set ; } /// <summary> /// 请求类型 /// </summary> public string ContentType { get ; private set ; } /// <summary> /// 上传的文件名 /// </summary> public string Filename { get ; private set ; } /// <summary> /// 上传的文件内容 /// </summary> public byte [] FileContents { get ; private set ; } /// <summary> /// 解析multipart/form-data格式的文件请求,默认编码为utf8 /// </summary> /// <param name="stream"></param> /// <param name="filePartName"></param> public HttpMultipartParser(Stream stream, string filePartName) { FilePartName = filePartName; Parse(stream, Encoding.UTF8); } /// <summary> /// 解析multipart/form-data格式的字符串 /// </summary> /// <param name="content"></param> public HttpMultipartParser( string content) { var array = Encoding.UTF8.GetBytes(content); var stream = new MemoryStream(array); Parse(stream, Encoding.UTF8); } /// <summary> /// 解析multipart/form-data格式的文件请求 /// </summary> /// <param name="stream"></param> /// <param name="encoding">编码</param> /// <param name="filePartName"></param> public HttpMultipartParser(Stream stream, Encoding encoding, string filePartName) { FilePartName = filePartName; Parse(stream, encoding); } private void Parse(Stream stream, Encoding encoding) { Success = false ; var data = ToByteArray(stream); var content = encoding.GetString(data); var delimiterEndIndex = content.IndexOf( "\r\n" , StringComparison.Ordinal); if (delimiterEndIndex > -1) { var delimiter = content.Substring(0, content.IndexOf( "\r\n" , StringComparison.Ordinal)).Trim(); var sections = content.Split( new [] {delimiter}, StringSplitOptions.RemoveEmptyEntries); foreach (var s in sections) { if (s.Contains( "Content-Disposition" )) { var nameMatch = new Regex( @"(?<=name\=\"")(.*?)(?=\"")" ).Match(s); var name = nameMatch.Value.Trim().ToLower(); if (name == FilePartName && ! string .IsNullOrEmpty(FilePartName)) { var re = new Regex( @"(?<=Content\-Type:)(.*?)(?=\r\n\r\n)" ); var contentTypeMatch = re.Match(content); re = new Regex( @"(?<=filename\=\"")(.*?)(?=\"")" ); var filenameMatch = re.Match(content); if (contentTypeMatch.Success && filenameMatch.Success) { ContentType = contentTypeMatch.Value.Trim(); Filename = filenameMatch.Value.Trim(); var startIndex = contentTypeMatch.Index + contentTypeMatch.Length + "\r\n\r\n" .Length; var delimiterBytes = encoding.GetBytes( "\r\n" + delimiter); var endIndex = IndexOf(data, delimiterBytes, startIndex); var contentLength = endIndex - startIndex; var fileData = new byte [contentLength]; Buffer.BlockCopy(data, startIndex, fileData, 0, contentLength); FileContents = fileData; } } else if (! string .IsNullOrWhiteSpace(name)) { var startIndex = nameMatch.Index + nameMatch.Length + "\r\n\r\n" .Length; Parameters.Add(name, s.Substring(startIndex).TrimEnd( '\r' , '\n' ).Trim()); } } } if (FileContents != null || Parameters.Count != 0) { Success = true ; } } } public static int IndexOf( byte [] searchWithin, byte [] serachFor, int startIndex) { var index = 0; var startPos = Array.IndexOf(searchWithin, serachFor[0], startIndex); if (startPos != -1) { while (startPos + index < searchWithin.Length) { if (searchWithin[startPos + index] == serachFor[index]) { index++; if (index == serachFor.Length) { return startPos; } } else { startPos = Array.IndexOf(searchWithin, serachFor[0], startPos + index); if (startPos == -1) { return -1; } index = 0; } } } return -1; } public static byte [] ToByteArray(Stream stream) { var buffer = new byte [32768]; using (var ms = new MemoryStream()) { while ( true ) { var read = stream.Read(buffer, 0, buffer.Length); if (read <= 0) { return ms.ToArray(); } ms.Write(buffer, 0, read); } } } } } |
调用示例
1 2 3 4 5 6 7 8 9 10 11 12 13 | HttpMultipartParser parser = new HttpMultipartParser(paramData); if (!parser.Success) { result.Code = -1; result.Message = "请求数据格式不能正确" ; return result; } if (!parser.Parameters.ContainsKey( "optid" ) || parser.Parameters[ "optid" ] == null || string .IsNullOrEmpty(parser.Parameters[ "optid" ])) { result.Code = -1; result.Message = "用户名不能为空" ; return result; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | public void Upload(Stream stream) { HttpMultipartParser parser = new HttpMultipartParser(stream, "image" ); if (parser.Success) { string user = HttpUtility.UrlDecode(parser.Parameters[ "user" ]); string title = HttpUtility.UrlDecode(parser.Parameters[ "title" ]); // Save the file somewhere File.WriteAllBytes(FILE_PATH + title + FILE_EXT, parser.FileContents); } } |
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

微信公众号搜索 “ 脚本之家 ” ,选择关注
程序猿的那些事、送书等活动等着你
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若内容造成侵权/违法违规/事实不符,请将相关资料发送至 reterry123@163.com 进行投诉反馈,一经查实,立即处理!
相关文章
C#中Forms.Timer、Timers.Timer、Threading.Timer的用法分析
这篇文章主要介绍了C#中Forms.Timer、Timers.Timer、Threading.Timer的用法分析,以实例形式较为详细的讲述了.NET Framework里面提供的三种Timer具体用法,需要的朋友可以参考下2014-10-10
最新评论