当前位置: 首页 > 面试题库 >

解析原始HTTP标头

南宫浩皛
2023-03-14
问题内容

我有一个原始HTTP字符串,我想代表一个对象中的字段。有什么方法可以解析HTTP字符串中的各个标头?

'GET /search?sourceid=chrome&ie=UTF-8&q=ergterst HTTP/1.1\r\nHost: www.google.com\r\nConnection: keep-alive\r\nAccept: application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5\r\nUser-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_6; en-US) AppleWebKit/534.13 (KHTML, like Gecko) Chrome/9.0.597.45 Safari/534.13\r\nAccept-Encoding: gzip,deflate,sdch\r\nAvail-Dictionary: GeNLY2f-\r\nAccept-Language: en-US,en;q=0.8\r\n
[...]'

问题答案:

更新: 现在是2019年,所以在程序员尝试使用该代码的混乱评论之后,我为Python 3重写了此答案。原始的Python
2代码现在位于答案的底部。

标准库中有出色的工具,可以解析RFC
821标头,也可以解析整个HTTP请求。这是一个示例请求字符串(请注意,即使为了方便阅读,我们将其分成几行,Python仍将其视为一个大字符串),可以将其提供给示例:

request_text = (
    b'GET /who/ken/trust.html HTTP/1.1\r\n'
    b'Host: cm.bell-labs.com\r\n'
    b'Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3\r\n'
    b'Accept: text/html;q=0.9,text/plain\r\n'
    b'\r\n'
)

正如@TryPyPy指出的那样,您可以使用Python的电子邮件库来解析标头-
尽管我们应该添加一个结果Message,一旦完成创建后,结果对象就像标头的字典:

from email.parser import BytesParser
request_line, headers_alone = request_text.split(b'\r\n', 1)
headers = BytesParser().parsebytes(headers_alone)

print(len(headers))     # -> "3"
print(headers.keys())   # -> ['Host', 'Accept-Charset', 'Accept']
print(headers['Host'])  # -> "cm.bell-labs.com"

但这当然会忽略请求行,或者让您自己解析它。事实证明,有一个更好的解决方案。

如果使用标准库,标准库将为您解析HTTP
BaseHTTPRequestHandler。尽管其文档有点晦涩(标准库中整个HTTP和URL工具套件都存在问题),但您要做的只是解析(a)将字符串包装在BytesIO()(b)中,raw_requestline因此它随时可以解析,并且(c)捕获解析期间发生的任何错误代码,而不是让它尝试将其写回客户端(因为我们没有密码!)。

因此,这是我们对标准库类的专门化:

from http.server import BaseHTTPRequestHandler
from io import BytesIO

class HTTPRequest(BaseHTTPRequestHandler):
    def __init__(self, request_text):
        self.rfile = BytesIO(request_text)
        self.raw_requestline = self.rfile.readline()
        self.error_code = self.error_message = None
        self.parse_request()

    def send_error(self, code, message):
        self.error_code = code
        self.error_message = message

再一次,我希望标准库的人们意识到HTTP解析应该以一种不需要我们编写9行代码来正确调用的方式进行,但是您能做什么?这是您将如何使用此简单类的方法:

# Using this new class is really easy!

request = HTTPRequest(request_text)

print(request.error_code)       # None  (check this first)
print(request.command)          # "GET"
print(request.path)             # "/who/ken/trust.html"
print(request.request_version)  # "HTTP/1.1"
print(len(request.headers))     # 3
print(request.headers.keys())   # ['Host', 'Accept-Charset', 'Accept']
print(request.headers['host'])  # "cm.bell-labs.com"

如果解析期间发生错误,error_code则不会是None

# Parsing can result in an error code and message

request = HTTPRequest(b'GET\r\nHeader: Value\r\n\r\n')

print(request.error_code)     # 400
print(request.error_message)  # "Bad request syntax ('GET')"

我更喜欢这样使用标准库,因为如果我尝试使用正则表达式自己重新实现Internet规范,我怀疑它们已经遇到并解决了可能会困扰我的所有边缘情况。

旧的Python 2代码

这是此答案的原始代码,可追溯到我第一次编写它时:

request_text = (
    'GET /who/ken/trust.html HTTP/1.1\r\n'
    'Host: cm.bell-labs.com\r\n'
    'Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3\r\n'
    'Accept: text/html;q=0.9,text/plain\r\n'
    '\r\n'
    )

和:

# Ignore the request line and parse only the headers

from mimetools import Message
from StringIO import StringIO
request_line, headers_alone = request_text.split('\r\n', 1)
headers = Message(StringIO(headers_alone))

print len(headers)     # -> "3"
print headers.keys()   # -> ['accept-charset', 'host', 'accept']
print headers['Host']  # -> "cm.bell-labs.com"

和:

from BaseHTTPServer import BaseHTTPRequestHandler
from StringIO import StringIO

class HTTPRequest(BaseHTTPRequestHandler):
    def __init__(self, request_text):
        self.rfile = StringIO(request_text)
        self.raw_requestline = self.rfile.readline()
        self.error_code = self.error_message = None
        self.parse_request()

    def send_error(self, code, message):
        self.error_code = code
        self.error_message = message

和:

# Using this new class is really easy!

request = HTTPRequest(request_text)

print request.error_code       # None  (check this first)
print request.command          # "GET"
print request.path             # "/who/ken/trust.html"
print request.request_version  # "HTTP/1.1"
print len(request.headers)     # 3
print request.headers.keys()   # ['accept-charset', 'host', 'accept']
print request.headers['host']  # "cm.bell-labs.com"

和:

# Parsing can result in an error code and message

request = HTTPRequest('GET\r\nHeader: Value\r\n\r\n')

print request.error_code     # 400
print request.error_message  # "Bad request syntax ('GET')"


 类似资料:
  • 问题内容: 我正在处理HTTP流量数据集,该数据集由完整的POST和GET请求组成,如下所示。我已经用Java编写了代码,该代码已经分离了每个请求,并将其另存为数组列表中的字符串元素。 现在我很困惑如何在Java中解析这些原始HTTP请求,有什么方法比手动解析更好吗? 问题答案: 我[正在]处理[HTTP]流量数据集,该数据集由完整的POST和GET请求组成 因此,您想解析包含多个HTTP请求的文

  • 我正在研究HTTP流量数据集,它由完整的POST和GET请求组成,如下所示。我用java编写了代码,将每个请求分开,并将其保存为数组列表中的字符串元素。现在我很困惑如何在java中解析这些原始HTTP请求,有什么方法比手动解析更好吗?

  • 问题内容: 有什么方法可以获取原始响应的HTTP标头? 该方法对我不起作用,因为服务器吐出了多个“ Set-Cookie”,其中一些丢失了。 问题答案: 该方法对我不起作用 您是在的情况下问这个的吗?不可以,无法使用原始HTTP响应标头。您需要退回到低级的Socket编程。这是一个SSCCE,只需复制“ 粘贴 ”即可运行它。 为了避免每个尝试此代码片段的人都使SO过载,输出如下所示: 要了解有关以

  • 我试图从原始HTTP请求消息中提取一些信息(如下所示),并将它们存储到org.apache.HTTP.message.basicHttpRequest(https://hc.apache.org/httpComponents-core-ga/httpcore/apidocs/index.html)类的实例中。 我能够使用org.apache.http.message.BasicLineParser

  • 本文向大家介绍详解http访问解析流程原理,包括了详解http访问解析流程原理的使用技巧和注意事项,需要的朋友参考一下 详解http访问解析流程原理 http访问网址域名解析流程: 1、在浏览器中输入www.qq.com域名,操作系统会先检查自己本地的hosts文件是否有这个网址映射关系,如果有,就先调用这个IP地址映射,完成域名解析。 2、如果hosts里没有这个域名的映射,则查找本地DNS解析

  • 问题内容: 我从其他地方的日志中附带了http响应标头。在我的日志文件中,我有类似以下内容: 给定上面的字符串,我如何将其解析为net / http中所述的Header对象。一种方法是自己分割字符串并映射键,值…但是我希望避免手动操作,而使用标准的(或维护良好的第3方)库来解析它…任何指针? 问题答案: 内置的解析器位于textproto中。您可以直接使用它,也可以添加伪造的HTTP请求标头并在h