C#如何解析http报文
作者:mrr 发布时间:2022-11-22 23:20:56
标签:http,解析
下面通过一段内容有文字说明有代码分析,并附有展示图供大家学习。
要解析HTTP报文,需要实现以下操作:
读取HTTP报头提供的各种属性
分析属性值,从中获取内容编码和字符集编码
将报头数据和内容进行分离
判断内容是否文本还是二进制,如果是二进制的则不进行处理
如果内容是文本,按报头中提供的内容编码和字符集编码进行解压缩和解码
目前没有找到.Net框架内置的解析方法,理论上HttpClient等类在内部应该已经实现了解析,但不知为何没有公开这些处理方法。(亦或是我没找到)
那么只能自己来解析这些数据了。
我们先来看看这个经过gzip压缩的文本内容的HTTP报文:
这里提供一个老外写的简陋的解析类(已经过修改,原代码中存在一些严重BUG):
public enum HTTPHeaderField
{
Accept = 0,
Accept_Charset = 1,
Accept_Encoding = 2,
Accept_Language = 3,
Accept_Ranges = 4,
Authorization = 5,
Cache_Control = 6,
Connection = 7,
Cookie = 8,
Content_Length = 9,
Content_Type = 10,
Date = 11,
Expect = 12,
From = 13,
Host = 14,
If_Match = 15,
If_Modified_Since = 16,
If_None_Match = 17,
If_Range = 18,
If_Unmodified_Since = 19,
Max_Forwards = 20,
Pragma = 21,
Proxy_Authorization = 22,
Range = 23,
Referer = 24,
TE = 25,
Upgrade = 26,
User_Agent = 27,
Via = 28,
Warn = 29,
Age = 30,
Allow = 31,
Content_Encoding = 32,
Content_Language = 33,
Content_Location = 34,
Content_Disposition = 35,
Content_MD5 = 36,
Content_Range = 37,
ETag = 38,
Expires = 39,
Last_Modified = 40,
Location = 41,
Proxy_Authenticate = 42,
Refresh = 43,
Retry_After = 44,
Server = 45,
Set_Cookie = 46,
Trailer = 47,
Transfer_Encoding = 48,
Vary = 49,
Warning = 50,
WWW_Authenticate = 51
};
class HTTPHeader
{
#region PROPERTIES
private string[] m_StrHTTPField = new string[52];
private byte[] m_byteData = new byte[4096];
public string[] HTTPField
{
get { return m_StrHTTPField; }
set { m_StrHTTPField = value; }
}
public byte[] Data
{
get { return m_byteData; }
set { m_byteData = value; }
}
#endregion
// convertion
System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
#region CONSTRUCTEUR
/// <summary>
/// Constructeur par défaut - non utilisé
/// </summary>
private HTTPHeader()
{ }
public HTTPHeader(byte[] ByteHTTPRequest)
{
string HTTPRequest = encoding.GetString(ByteHTTPRequest);
try
{
int IndexHeaderEnd;
string Header;
// Si la taille de requête est supérieur ou égale à 1460, alors toutes la chaine est l'entête http
if (HTTPRequest.Length <= 1460)
Header = HTTPRequest;
else
{
IndexHeaderEnd = HTTPRequest.IndexOf("\r\n\r\n");
Header = HTTPRequest.Substring(0, IndexHeaderEnd);
Data = ByteHTTPRequest.Skip(IndexHeaderEnd + 4).ToArray();
}
HTTPHeaderParse(Header);
}
catch (Exception)
{ }
}
#endregion
#region METHODES
private void HTTPHeaderParse(string Header)
{
#region HTTP HEADER REQUEST & RESPONSE
HTTPHeaderField HHField;
string HTTPfield, buffer;
int Index;
foreach (int IndexHTTPfield in Enum.GetValues(typeof(HTTPHeaderField)))
{
HHField = (HTTPHeaderField)IndexHTTPfield;
HTTPfield = "\n" + HHField.ToString().Replace('_', '-') + ": "; //Ajout de \n devant pour éviter les doublons entre cookie et set_cookie
// Si le champ n'est pas présent dans la requête, on passe au champ suivant
Index = Header.IndexOf(HTTPfield);
if (Index == -1)
continue;
buffer = Header.Substring(Index + HTTPfield.Length);
Index = buffer.IndexOf("\r\n");
if (Index == -1)
m_StrHTTPField[IndexHTTPfield] = buffer.Trim();
else
m_StrHTTPField[IndexHTTPfield] = buffer.Substring(0, Index).Trim();
//Console.WriteLine("Index = " + IndexHTTPfield + " | champ = " + HTTPfield.Substring(1) + " " + m_StrHTTPField[IndexHTTPfield]);
}
// Affichage de tout les champs
/*for (int j = 0; j < m_StrHTTPField.Length; j++)
{
HHField = (HTTPHeaderField)j;
Console.WriteLine("m_StrHTTPField[" + j + "]; " + HHField + " = " + m_StrHTTPField[j]);
}
*/
#endregion
}
#endregion
}
编写以下代码以实现解析文件:
class Program
{
static void Main(string[] args)
{
SRART: Console.WriteLine("输入待解析的HTTP报文数据文件完整路径:");
var filename = Console.ReadLine();
try
{
FileStream fs = new FileStream(filename, FileMode.Open);
BinaryReader br = new BinaryReader(fs);
var data = br.ReadBytes((int)fs.Length);
var header = new HTTPHeader(data);
var x = 0;
foreach (var f in header.HTTPField)
{
if (!String.IsNullOrEmpty(f))
{
Console.WriteLine($"[{x:00}] - {(HTTPHeaderField) x} : {f}");
}
x++;
}
Console.WriteLine($"总数据尺寸{fs.Length}字节,实际数据尺寸{header.Data.Length}字节");
Console.WriteLine(Encoding.UTF8.GetString(header.Data));
Console.WriteLine();
br.Close();
fs.Close();
}
catch (Exception e)
{
Console.WriteLine(e);
}
goto SRART;
}
}
这里还未实现gzip解压缩和字符解码,直接用UTF8解码输出的。(需要时再写吧,都是体力活儿~)
效果图展示:
下面的图是没有经过gzip压缩过的数据。
0
投稿
猜你喜欢
- 那么什么是性能测试,它与功能测试有什么样的区别?性能测试是通过自动化的测试工具模拟多种正常、峰值以及异常负载条件来对系统的各项性能指标进行测
- 容器适配器我们可以看出,栈中没有空间配置器(内存池),而是适配器适配器是一种设计模式(设计模式是一套被反复使用的、多数人知晓的、经过分类编目
- 本文实例介绍了基于socket和javaFX简单文件传输工具,分享给大家供大家参考,具体内容如下package application;im
- 1. Spring 是什么我们通常所说的 Spring 指的是 Spring Framework(Spring 框架),它是一个开源框架,有
- 一、实现对ScrollViewer样式的自定义主要包括:1、滚动条宽度设置2、滚动条颜色3、滚动条圆角4、滚动条拉动时的效果mouseove
- 前言:本篇文章将介绍Java多线程中的几个典型案例之单例模式,所谓单例模式,就是一个类只有一个实例对象,本文将着重介绍在多线程的背景下,单例
- 应用场景最近社区总有人发文章带上小广告,严重影响社区氛围,好气!对于这种类型的用户,就该永久拉黑!社区的安全框架使用了 spring-sec
- 引言备忘录模式经常可以遇到,譬如下面这些场景:浏览器回退:浏览器一般有浏览记录,当我们在一个网页上点击几次链接之后,可在左上角点击左箭头回退
- 首先,你可能会见到如下提示:File encoding is disabled because .properties file (see
- Android Studio 打包 jar 及 aar 包创建工程 New -> Module -> Library在gradl
- 什么是注解?对于很多初次接触的开发者来说应该都有这个疑问?Annontation是Java5开始引入的新特征,中文名称叫注解。它提供了一种安
- 问题描述在使用poi-tl word模版工具时,发现生成的文档中,图片格式为嵌入型,有的图片甚至被表格遮挡一半。而自己想要的图片格式为上下型
- 目录前沿快速开始引入依赖定义接口配置类开始调用json序列化接口层面指定header:指定Encoder跟Decoder使用 * 注解详解@
- 1. 运行环境 Enviroment当 MyBatis 与不同的应用结合时,需要不同的事务管理机制。与 Spring 结合时,由 Sprin
- 什么是枚举?枚举是JDK5引入的新特性。在某些情况下,一个类的对象是固定的,就可以定义为枚举。在实际使用中,枚举类型也可以作为一种规范,保障
- 简单实现了下:import javax.crypto.BadPaddingException;import javax.crypto.Cip
- throw抛出异常的方式比较直接:if(age < 0){throw new MyException("年龄不能为负数!&q
- 本文实例为大家分享了C#实现XML文件读取的具体代码,供大家参考,具体内容如下using System.Collections;using
- 本文实例为大家分享了Spring实现默认标签解析流程的具体代码,供大家参考,具体内容如下承接上文,进入parseBeanDefinition
- C++/java 继承类的多态详解学过C++和Java的人都知道,他们二者由于都可以进行面向对象编程,而面向对象编程的三大特性就是封装、继承