首页 > 编程 > C# > 正文

C#如何解析http报文

2019-10-29 21:39:29
字体:
来源:转载
供稿:网友

这篇文章如果讲解了用C#如何解析http报文,要解析http报文,需要哪些操作呢?下面小编给大家整理相关资料,需要的朋友可以参考下

下面通过一段内容有文字说明有代码分析,并附有展示图供大家学习。

要解析HTTP报文,需要实现以下操作:

读取HTTP报头提供的各种属性

分析属性值,从中获取内容编码和字符集编码

将报头数据和内容进行分离

判断内容是否文本还是二进制,如果是二进制的则不进行处理

如果内容是文本,按报头中提供的内容编码和字符集编码进行解压缩和解码

目前没有找到.Net框架内置的解析方法,理论上HttpClient等类在内部应该已经实现了解析,但不知为何没有公开这些处理方法。(亦或是我没找到)

那么只能自己来解析这些数据了。

我们先来看看这个经过gzip压缩的文本内容的HTTP报文:

C#如何解析http报文

这里提供一个老外写的简陋的解析类(已经过修改,原代码中存在一些严重BUG):

 

 
  1. public enum HTTPHeaderField 
  2. Accept = 0, 
  3. Accept_Charset = 1, 
  4. Accept_Encoding = 2, 
  5. Accept_Language = 3, 
  6. Accept_Ranges = 4, 
  7. Authorization = 5, 
  8. Cache_Control = 6, 
  9. Connection = 7, 
  10. Cookie = 8, 
  11. Content_Length = 9, 
  12. Content_Type = 10, 
  13. Date = 11, 
  14. Expect = 12, 
  15. From = 13, 
  16. Host = 14, 
  17. If_Match = 15, 
  18. If_Modified_Since = 16, 
  19. If_None_Match = 17, 
  20. If_Range = 18, 
  21. If_Unmodified_Since = 19, 
  22. Max_Forwards = 20, 
  23. Pragma = 21, 
  24. Proxy_Authorization = 22, 
  25. Range = 23, 
  26. Referer = 24, 
  27. TE = 25, 
  28. Upgrade = 26, 
  29. User_Agent = 27, 
  30. Via = 28, 
  31. Warn = 29, 
  32. Age = 30, 
  33. Allow = 31, 
  34. Content_Encoding = 32, 
  35. Content_Language = 33, 
  36. Content_Location = 34, 
  37. Content_Disposition = 35, 
  38. Content_MD5 = 36, 
  39. Content_Range = 37, 
  40. ETag = 38, 
  41. Expires = 39, 
  42. Last_Modified = 40, 
  43. Location = 41, 
  44. Proxy_Authenticate = 42, 
  45. Refresh = 43, 
  46. Retry_After = 44, 
  47. Server = 45, 
  48. Set_Cookie = 46, 
  49. Trailer = 47, 
  50. Transfer_Encoding = 48, 
  51. Vary = 49, 
  52. Warning = 50, 
  53. WWW_Authenticate = 51 
  54. }; 
  55. class HTTPHeader 
  56. #region PROPERTIES 
  57. private string[] m_StrHTTPField = new string[52]; 
  58. private byte[] m_byteData = new byte[4096]; 
  59. public string[] HTTPField 
  60. get { return m_StrHTTPField; } 
  61. set { m_StrHTTPField = value; } 
  62. public byte[] Data 
  63. get { return m_byteData; } 
  64. set { m_byteData = value; } 
  65. #endregion 
  66. // convertion 
  67. System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding(); 
  68. #region CONSTRUCTEUR 
  69. /// <summary> 
  70. /// Constructeur par défaut - non utilisé 
  71. /// </summary> 
  72. private HTTPHeader() 
  73. { } 
  74. public HTTPHeader(byte[] ByteHTTPRequest) 
  75. string HTTPRequest = encoding.GetString(ByteHTTPRequest); 
  76. try 
  77. int IndexHeaderEnd; 
  78. string Header; 
  79. // Si la taille de requête est supérieur ou égale à 1460, alors toutes la chaine est l'entête http 
  80. if (HTTPRequest.Length <= 1460) 
  81. Header = HTTPRequest; 
  82. else 
  83. IndexHeaderEnd = HTTPRequest.IndexOf("/r/n/r/n"); 
  84. Header = HTTPRequest.Substring(0, IndexHeaderEnd); 
  85. Data = ByteHTTPRequest.Skip(IndexHeaderEnd + 4).ToArray(); 
  86. HTTPHeaderParse(Header); 
  87. catch (Exception) 
  88. { } 
  89. #endregion 
  90. #region METHODES 
  91. private void HTTPHeaderParse(string Header) 
  92. #region HTTP HEADER REQUEST & RESPONSE 
  93. HTTPHeaderField HHField; 
  94. string HTTPfield, buffer; 
  95. int Index; 
  96. foreach (int IndexHTTPfield in Enum.GetValues(typeof(HTTPHeaderField))) 
  97. HHField = (HTTPHeaderField)IndexHTTPfield; 
  98. HTTPfield = "/n" + HHField.ToString().Replace('_''-') + ": "//Ajout de /n devant pour éviter les doublons entre cookie et set_cookie 
  99. // Si le champ n'est pas présent dans la requête, on passe au champ suivant 
  100. Index = Header.IndexOf(HTTPfield); 
  101. if (Index == -1) 
  102. continue
  103. buffer = Header.Substring(Index + HTTPfield.Length); 
  104. Index = buffer.IndexOf("/r/n"); 
  105. if (Index == -1) 
  106. m_StrHTTPField[IndexHTTPfield] = buffer.Trim(); 
  107. else 
  108. m_StrHTTPField[IndexHTTPfield] = buffer.Substring(0, Index).Trim(); 
  109. //Console.WriteLine("Index = " + IndexHTTPfield + " | champ = " + HTTPfield.Substring(1) + " " + m_StrHTTPField[IndexHTTPfield]); 
  110. // Affichage de tout les champs 
  111. /*for (int j = 0; j < m_StrHTTPField.Length; j++) 
  112. { 
  113. HHField = (HTTPHeaderField)j; 
  114. Console.WriteLine("m_StrHTTPField[" + j + "]; " + HHField + " = " + m_StrHTTPField[j]); 
  115. } 
  116. */ 
  117. #endregion 
  118. #endregion 

编写以下代码以实现解析文件:

 

 
  1. class Program 
  2. static void Main(string[] args) 
  3. SRART: Console.WriteLine("输入待解析的HTTP报文数据文件完整路径:"); 
  4. var filename = Console.ReadLine(); 
  5. try 
  6. FileStream fs = new FileStream(filename, FileMode.Open); 
  7. BinaryReader br = new BinaryReader(fs); 
  8. var data = br.ReadBytes((int)fs.Length); 
  9. var header = new HTTPHeader(data); 
  10. var x = 0; 
  11. foreach (var f in header.HTTPField) 
  12. if (!String.IsNullOrEmpty(f)) 
  13. Console.WriteLine($"[{x:00}] - {(HTTPHeaderField) x} : {f}"); 
  14. x++; 
  15. Console.WriteLine($"总数据尺寸{fs.Length}字节,实际数据尺寸{header.Data.Length}字节"); 
  16. Console.WriteLine(Encoding.UTF8.GetString(header.Data)); 
  17. Console.WriteLine(); 
  18. br.Close(); 
  19. fs.Close();  
  20. catch (Exception e) 
  21. Console.WriteLine(e); 
  22. goto SRART; 

这里还未实现gzip解压缩和字符解码,直接用UTF8解码输出的。(需要时再写吧,都是体力活儿~)

效果图展示:

C#如何解析http报文

C#如何解析http报文

下面的图是没有经过gzip压缩过的数据。

以上就是用C#如何解析http报文的全部内容,哪位大侠还有好的方法欢迎提出宝贵意见,喜欢大家喜欢以上内容所述。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表