Có các công cụ tuyệt vời trong Thư viện chuẩn để phân tích cú pháp tiêu đề RFC 821 và cũng để phân tích toàn bộ các yêu cầu HTTP. Dưới đây là một chuỗi ví dụ yêu cầu (lưu ý rằng Python đối xử với nó như một chuỗi lớn, mặc dù chúng ta đang phá vỡ nó trên một số dòng cho dễ đọc) mà chúng ta có thể ăn các ví dụ của tôi:
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'
)
Như @TryPyPy chỉ ra, bạn có thể sử dụng mimetools.Message
để phân tích các tiêu đề - mặc dù chúng ta nên thêm rằng kết quả Message
hành vi đối tượng như một cuốn từ điển các tiêu đề khi bạn đang thực hiện tạo ra 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"
Nhưng điều này, tất nhiên, bỏ qua những dòng yêu cầu, hoặc làm cho bạn phân tích nó cho mình. Nó chỉ ra rằng có một giải pháp tốt hơn nhiều.
Thư viện chuẩn sẽ phân tích cú pháp HTTP cho bạn nếu bạn sử dụng BaseHTTPRequestHandler
. Mặc dù tài liệu của nó hơi mơ hồ - một vấn đề với toàn bộ bộ công cụ HTTP và URL trong Thư viện Chuẩn - tất cả những gì bạn phải làm để làm cho nó phân tích chuỗi là (a) quấn chuỗi của bạn trong một StringIO()
, (b) đọc raw_requestline
để nó sẵn sàng để được phân tích cú pháp, và (c) nắm bắt bất kỳ mã lỗi nào xảy ra trong quá trình phân tích cú pháp thay vì để nó cố gắng ghi chúng trở lại máy khách (vì chúng tôi không có)!
Vì vậy, đây là chuyên môn của chúng ta về lớp Thư viện Tiêu chuẩn:
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
Một lần nữa, tôi muốn các folks thư viện chuẩn đã nhận ra rằng phân tích cú pháp HTTP nên được chia ra theo một cách mà không đòi hỏi chúng ta phải viết chín dòng mã để gọi đúng, nhưng bạn có thể làm gì? Đây là cách bạn sẽ sử dụng lớp đơn giản này:
# 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"
Nếu có một lỗi trong quá trình phân tích cú pháp, các error_code
sẽ không None
:
# 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')"
Tôi thích sử dụng bộ thư viện chuẩn như thế này bởi vì tôi nghi ngờ rằng họ đã gặp phải và giải quyết bất kỳ trường hợp cạnh nào có thể gây khó chịu cho tôi nếu tôi cố gắng triển khai lại một đặc tả Internet với các biểu thức chính quy.
Có cách nào để làm điều này trong python3? – Broseph
mimetools không còn được dùng kể từ 2.3 –
@Broseph Xem câu trả lời của Gowtham. – JeromeJ