You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Socket发起HTTP请求时遭遇400 Bad Request问题求助

解决Python手动构造HTTP GET请求返回400 Bad Request的问题

当运行你提供的代码并输入users.uop.gr/~kyianno/这类链接时,会收到400错误,核心问题出在HTTP协议细节处理、状态码解析逻辑以及代码边界情况处理上,以下是具体问题和修正方案:

原代码的核心问题

  • HTTP请求换行符不符合规范:HTTP 1.1协议要求请求头的每行结尾必须是\r\n(回车+换行),原代码使用单个\n,服务器无法正确解析请求格式,直接返回400错误。
  • 状态码解析逻辑完全错误:原代码尝试用struct.unpack("!H", response[:2])[0]解析状态码,但HTTP响应开头是HTTP/1.1 200 OK\r\n这类文本格式,前两个字节是HT,转成整数完全不是状态码,导致后续逻辑无法触发。
  • 文件路径定义存在漏洞:仅在目录不存在时定义file_path,若目录已存在,后续执行open(file_path)会抛出NameError。
  • 请求路径边界处理缺失:若输入纯域名(如users.uop.gr),拆分后object_name为空,此时GET请求会变成GET HTTP/1.1(路径为空),属于无效请求。

修正后的代码

import socket
import os

def parse_hyperlink(hyperlink):
    # 处理路径为空的情况,默认设为/
    parts = hyperlink.split("/")
    hostname = parts[0]
    if len(parts) > 1:
        object_name = "/" + "/".join(parts[1:])
    else:
        object_name = "/"
    # 避免末尾多斜杠的问题(可选,不影响但更规范)
    if object_name == "//":
        object_name = "/"
    return hostname, object_name

def get_host_address(hostname):
    host_address = socket.gethostbyname(hostname)
    return host_address

def main():
    hyperlink = input("Enter a hyperlink: ")
    hostname, object_name = parse_hyperlink(hyperlink)
    host_address = get_host_address(hostname)

    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server_socket.connect((host_address, 80))

    # 使用HTTP规范的\r\n换行符
    request = f"GET {object_name} HTTP/1.1\r\n"
    request += f"Host: {hostname}\r\n"
    request += "Connection: close\r\n"  # 显式关闭连接,方便接收完整响应
    request += "\r\n"  # 空行表示请求头结束

    server_socket.sendall(request.encode("utf-8"))

    response = b""
    while True:
        data = server_socket.recv(1024)  # 增大缓冲区,提高接收效率
        if not data:
            break
        response += data

    # 正确解析状态码:拆分响应头文本
    response_str = response.decode("utf-8")
    status_line = response_str.split("\r\n")[0]
    status_code = int(status_line.split()[1])

    if status_code == 200:
        desktop_path = os.path.expanduser("~/Desktop")
        directory = os.path.join(desktop_path, "my_directory")
        os.makedirs(directory, exist_ok=True)  # 直接创建,已存在则忽略
        file_path = os.path.join(directory, "response.html")

        # 分离响应头和响应体,只保存响应体(可选,若要完整响应可去掉切片)
        body_start = response_str.find("\r\n\r\n") + 4
        with open(file_path, "wb") as f:
            f.write(response[body_start:])

    print(response_str)

    server_socket.close()

if __name__ == "__main__":
    main()

关键修改说明

  1. 修正HTTP换行符:所有请求头换行使用\r\n,符合HTTP 1.1协议规范,解决400错误的核心原因。
  2. 正确解析状态码:从响应的第一行文本中提取状态码,逻辑符合HTTP响应格式。
  3. 修复文件路径逻辑:使用os.makedirs(directory, exist_ok=True)确保目录存在,无论目录是否已创建都定义file_path。
  4. 完善路径处理:当输入纯域名时,自动将请求路径设为/,避免无效请求。
  5. 优化接收缓冲区:将recv(255)改为recv(1024),提高大响应的接收效率;添加Connection: close头,确保服务器发送完响应后关闭连接,避免无限等待。

内容的提问来源于stack exchange,提问作者Τηλέμαχος Γκουλέτσας

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 04:05:40