我应该如何将 HTTP 标头从字节解码为字符串?

use*_*244 2 python header http

基本上,我正在尝试从头开始用 python 创建一个小型网络服务器(只是为了学习),但我在解码标头时遇到了问题。代码归结为以下内容(我已将其简化为仅与问题相关的代码):

import socket

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(('', 80))
sock.listen(1)

while True:
    conn, addr = sock.accept()

    print(addr[0])
    request = conn.recv(2048).decode('utf-8')

    headers = (
        'HTTP/1.0 200 OK',
        'Content-Type: text/html'
    )

    content = 'success'

    response = "\n".join(headers) + "\r\n\r\n" + content

    conn.sendall(bytes(response, 'UTF-8'))

    conn.close()
Run Code Online (Sandbox Code Playgroud)

我安装了 Firefox 的插件 HttpRequester 来摆弄我当前的内容并尝试附加文件,这导致了以下错误:

UnicodeDecodeError: 'utf-8' codec can't decode byte 0x90 in position 386: invalid start byte

我该如何解决这个问题?我应该将其包装在 try: 中并忽略导致此类异常的请求吗?

Mar*_*ers 5

RFC 7230对于字段解析有这样的说法:

从历史上看,HTTP 允许字段内容包含 ISO-8859-1 字符集 [ISO-8859-1] 中的文本,仅通过使用 [RFC2047] 编码来支持其他字符集。实际上,大多数 HTTP 标头字段值仅使用 US-ASCII 字符集 [USASCII] 的子集。新定义的头字段应该将其字段值限制为 US-ASCII 八位字节。接收者应该将字段内容(obs-text)中的其他八位字节视为不透明数据。

其中RFC 2047为您提供了使用其他字符集的扩展机制;无论如何,这些都会被编码为 ASCII,并且需要额外的步骤来解码。就我个人而言,我从未见过此类标头实际用于 HTTP 通信。

因此,您可以安全地假设所有标头都可以解码为 Latin-1,并且 RFC 2047 标头可以稍后单独处理:

request = conn.recv(2048)
headers, sep, body = request.partition(b'\r\n\r\n')
headers = headers.decode('latin1') 
Run Code Online (Sandbox Code Playgroud)

这确实假设所有标头都适合这 2048 个字节。

Latin-1 (ISO-8859-1) 直接一对一地将字节解码为 Unicode 代码点;即使对于那些应该被视为不透明数据的字段也可以通过这种方式进行解码,即使这可能是这些标头的错误编解码器。实际上,您可能不会遇到此类标头,即使遇到,您也不会关心这些标头。重要的标头都是 ASCII 编码的。