C#如何自定义multipart/form-data的解析器
作者:张云勇 发布时间:2023-12-04 18:59:03
标签:C#,multipart,form-data,解析器
使用WebSocketSharp自定义实现Web服务时,无法解析multipart/form-data请求的数据。
通过查找资料,采用以下方式实现multipart/form-data的解析器。
解析辅助类
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);
}
}
}
}
}
调用示例
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;
}
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);
}
}
来源:https://blog.csdn.net/xiaoyong_net/article/details/107688427
0
投稿
猜你喜欢
- 相信最近看过我的文章的朋友对于Microsoft.Extensions.ObjectPool不陌生;复用、池化是在很多高性能场景的优化技巧,
- 数组是一种数据结构,其声明方式如下:type[] arrayName;数组具有以下属性: 1.数组可以是
- Servlet3.0的出现是servlet史上最大的变革,其中的许多新特性大大的简化了web应用的开发,为广大劳苦的程序员减轻了压力,提高了
- 线程安全解决方案synchronized,ReentrantLock,Atomic 使用场景描述在实际开发过程中如果服务量,请求频繁,就会经
- 现公司架构大佬在项目中使用了 mybatis-generator-gui ,这是一款开源图形化 MyBatis 代码生成工具,使用起来相当的
- 网络编程TCP实现聊天的前提还需要掌握IO流,话不多说,直接上代码!客户端:package com.kuang.lesson02;impor
- 1.前置准备默认服务器上的hadoop服务已经启动本地如果是windows环境,需要本地配置下hadoop的环境变量本地配置hadoop的环
- 若代理类在程序运行前就已经存在,那么这种代理方式被成为 静态代理 ,这种情况下的代理类通常都是我们在Java代码中定义的。 通常情况下, 静
- springboot扩展MVC自定义 config -> SpringMvcConfig.java下边就是扩展springMVC的模板
- 这几年一直在做手机上和电视盒的App,几乎没有考虑过横竖屏切换的问题。电视盒好说,横屏不变,你要是给它设计个竖屏人家也没机会使;而手机上的应
- 前言两个数据结构:顺序表和链表数据结构是一门学科,和语言无关。数据 + 结构:一种描述和组织数据的方式。1. 顺序表顺序表是用一段物理地址连
- 适配器(Adapter)模式:适配器模式把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一
- 一、运算符运算符包括下面几种:算术运算符赋值运算符比较运算符逻辑运算符位运算符三目运算符最不常用的是位运算符,但也是最接近计算机底层的。1、
- 一、项目简述功能: 用户分为患者,医生,管理员,患者可进行注册选择医生 挂号,选择日期,选择号源,医生可进行接诊,管理员可 对用户,医生信息
- 本文实例展示了C#自定义函数NetxtString实现生成随机字符串的方法,在进行C#项目开发中非常实用!分享给大家供大家参考。一、生成随机
- RestTemplate未设置超时时间,导致RabbitMQ队列大量堆积,消费者假死,不进行消费,类似线程堵塞。排查:从日志排查问题,在从进
- 一、饿汉式单例类public class Singleton { privat
- 基本概念:类加载的过程大致分为三个阶段1、加载阶段:本阶段主要把class的二进制代码加载进入JVM,并且进行常量池(类名,方法名,字段名)
- 一个框架的使用,必然离不开其中的组件支持。我们在下载完mybatis框架后,因为大部分的内部结构还没有启动,就要手动的对其进行配置。在之前有
- 一、Synchronized的基本使用Synchronized是Java中解决并发问题的一种最常用的方法,也是最简单的一种方法。Synchr