Python 带套接字的 GET 请求 - 400 错误请求

Python GET request with sockets - 400 Bad request

我编写此代码是为了仅使用 python 套接字手动发出 GET 请求。它在 2016 年我编写它时运行得非常好,但现在我再次需要它并且我不断收到错误代码 400 错误请求。我尝试切换 python 版本,但它仍然是一样的。我一直在浏览 Whosebug 问题,问的问题或多或少与我所做的相同,但我就是无法让它工作。如果有人能帮助我,我将不胜感激。这是我的代码,我删除了所有 IO,只发布了网络代码。

URL_PATTERN = re.compile("^(.*://)?([A-Za-z0-9\-\.]+)(:[0-9]+)?(.*)$")
HEADER_END = re.compile("\r\n\r\n")

URL_DATA = re.match(URL_PATTERN, INPUT_URL)
PROTOCOL = URL_DATA.groups()[0][:-3]
HOSTNAME = URL_DATA.groups()[1]
PATHNAME = URL_DATA.groups()[3] if URL_DATA.groups()[3] != "" else "/"
PORT = 80 if PROTOCOL == "http" else 443
BUFFER_SIZE = 4096

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOSTNAME, PORT))

s.send("GET " + PATHNAME + " HTTP/1.1\r\nHost: " + HOSTNAME + "\r\nConnection: close\r\n\r\n")

resp = s.recv(BUFFER_SIZE)
HEADER_INDEX = re.search(HEADER_END, resp).start()
HTTP_RESPONSE_HEADER = resp[:HEADER_INDEX]

s.close()

当我运行我的程序在URLhttps://doc.rust-lang.org/book/2018-edition/foreword.html

我程序中的变量具有以下值:

端口: 443

协议:https

主机名:doc.rust-lang.org

路径名: /book/2018-edition/foreword.html

然后我得到了 400 错误的请求代码。我不明白我做错了什么,如果能得到任何帮助,我将不胜感激。

我相信这都是关于 SSL 的。作为参考,您可以查看此问题 .

我建议你使用:

context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)

并创建安全套接字:

s_sock = context.wrap_socket(s, server_hostname=HOSTNAME)
s_sock.connect((HOSTNAME, PORT))

此外,您可能需要对消息进行编码。

最后您的代码可能如下所示:

import re
import socket
import ssl

URL_PATTERN = re.compile("^(.*://)?([A-Za-z0-9\-\.]+)(:[0-9]+)?(.*)$")
HEADER_END = re.compile("\r\n\r\n")

INPUT_URL = "https://doc.rust-lang.org/book/2018-edition/foreword.html"

context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)

URL_DATA = re.match(URL_PATTERN, INPUT_URL)
PROTOCOL = URL_DATA.groups()[0][:-3]
HOSTNAME = URL_DATA.groups()[1]
PATHNAME = URL_DATA.groups()[3] if URL_DATA.groups()[3] != "" else "/"
PORT = 80 if PROTOCOL == "http" else 443
BUFFER_SIZE = 4096

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s_sock = context.wrap_socket(s, server_hostname=HOSTNAME)
s_sock.connect((HOSTNAME, PORT))

message = "GET " + PATHNAME + " HTTP/1.1\r\nHost: " + HOSTNAME + "\r\nConnection: close\r\n\r\n"
s_sock.send(message.encode('utf-8'))

resp = bytearray()
while True:
    part = s_sock.recv(BUFFER_SIZE)
    if not part:
        break
    resp += part

s_sock.close()

resp_string = str(resp, 'utf-8')
HEADER_INDEX = re.search(HEADER_END, resp_string).start()
HTTP_RESPONSE_HEADER = resp_string[:HEADER_INDEX]