C#如何解析http報(bào)文
下面通過一段內(nèi)容有文字說明有代碼分析,并附有展示圖供大家學(xué)習(xí)。
要解析HTTP報(bào)文,需要實(shí)現(xiàn)以下操作:
讀取HTTP報(bào)頭提供的各種屬性
分析屬性值,從中獲取內(nèi)容編碼和字符集編碼
將報(bào)頭數(shù)據(jù)和內(nèi)容進(jìn)行分離
判斷內(nèi)容是否文本還是二進(jìn)制,如果是二進(jìn)制的則不進(jìn)行處理
如果內(nèi)容是文本,按報(bào)頭中提供的內(nèi)容編碼和字符集編碼進(jìn)行解壓縮和解碼
目前沒有找到.Net框架內(nèi)置的解析方法,理論上HttpClient等類在內(nèi)部應(yīng)該已經(jīng)實(shí)現(xiàn)了解析,但不知為何沒有公開這些處理方法。(亦或是我沒找到)
那么只能自己來解析這些數(shù)據(jù)了。
我們先來看看這個(gè)經(jīng)過gzip壓縮的文本內(nèi)容的HTTP報(bào)文:

這里提供一個(gè)老外寫的簡陋的解析類(已經(jīng)過修改,原代碼中存在一些嚴(yán)重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
}
編寫以下代碼以實(shí)現(xiàn)解析文件:
class Program
{
static void Main(string[] args)
{
SRART: Console.WriteLine("輸入待解析的HTTP報(bào)文數(shù)據(jù)文件完整路徑:");
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($"總數(shù)據(jù)尺寸{fs.Length}字節(jié),實(shí)際數(shù)據(jù)尺寸{header.Data.Length}字節(jié)");
Console.WriteLine(Encoding.UTF8.GetString(header.Data));
Console.WriteLine();
br.Close();
fs.Close();
}
catch (Exception e)
{
Console.WriteLine(e);
}
goto SRART;
}
}
這里還未實(shí)現(xiàn)gzip解壓縮和字符解碼,直接用UTF8解碼輸出的。(需要時(shí)再寫吧,都是體力活兒~)
效果圖展示:


下面的圖是沒有經(jīng)過gzip壓縮過的數(shù)據(jù)。
以上就是用C#如何解析http報(bào)文的全部內(nèi)容,哪位大俠還有好的方法歡迎提出寶貴意見,喜歡大家喜歡以上內(nèi)容所述。
- c#使用Socket發(fā)送HTTP/HTTPS請求的實(shí)現(xiàn)代碼
- C#使用HttpPost請求調(diào)用WebService的方法
- C#使用Http Post方式傳遞Json數(shù)據(jù)字符串調(diào)用Web Service
- C#請求http向網(wǎng)頁發(fā)送接收數(shù)據(jù)的方法
- C#根據(jù)http和ftp圖片地址獲取對應(yīng)圖片
- C#模擬http 發(fā)送post或get請求的簡單實(shí)例
- C#基于socket模擬http請求的方法
- C#使用IHttpModule接口修改http輸出的方法
- C#實(shí)現(xiàn)發(fā)送簡單HTTP請求的方法
- C#實(shí)現(xiàn)簡單的Http請求實(shí)例
- 實(shí)例詳解C#實(shí)現(xiàn)http不同方法的請求
相關(guān)文章
C#中Hashtable與Dictionary的用法對比及選擇
這篇文章主要介紹了C#中Hashtable與Dictionary的用法對比及選擇方式,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2025-03-03
C#創(chuàng)建自定義控件及添加自定義屬性和事件使用實(shí)例詳解
這篇文章主要給大家介紹了關(guān)于C#創(chuàng)建自定義控件及添加自定義屬性和事件使用的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用C#具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2020-05-05
.net C# 實(shí)現(xiàn)任意List的笛卡爾乘積算法代碼
笛卡爾(Descartes)乘積又叫直積。假設(shè)集合A={a,b},集合B={0,1,2},則兩個(gè)集合的笛卡爾積為{(a,0),(a,1),(a,2),(b,0),(b,1), (b,2)}。2013-05-05
C#中將UTC時(shí)間轉(zhuǎn)換為JST時(shí)間的實(shí)現(xiàn)方法
在C#中,將UTC時(shí)間轉(zhuǎn)換為JST(日本標(biāo)準(zhǔn)時(shí)間,即UTC+9)時(shí)間可以通過使用 DateTime 和 TimeZoneInfo 類來實(shí)現(xiàn),JST比UTC快9小時(shí),因此可以直接進(jìn)行轉(zhuǎn)換,本文將通過代碼示例給大家介紹C#中將UTC時(shí)間轉(zhuǎn)換為JST時(shí)間,需要的朋友可以參考下2025-01-01
C#實(shí)現(xiàn)DevExpress本地化實(shí)例詳解
這篇文章主要介紹了C#實(shí)現(xiàn)DevExpress本地化,以實(shí)例形式較為詳細(xì)的分析了DevExpress本地化的相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-08-08

