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

使用Python-requests访问IoT设备时响应头为空,因存在双重响应头

解决requests因双重HTTP响应头无法解析Set-Cookie的问题

遇到这种设备返回非法双重HTTP头的情况确实头疼,requests默认的解析器会因为响应不符合规范而无法正确解析头部信息,导致r.headers为空。不过我们可以绕过高层解析,直接读取原始响应数据来提取需要的Set-Cookie。

下面提供两种可行的方案:

方案1:直接使用Socket读取原始响应

这种方法最直接,完全绕过requests/urllib3的解析逻辑,自己处理原始HTTP数据:

import socket

def extract_set_cookies(host, path, port=80):
    # 建立TCP连接并设置超时
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.settimeout(10)
    try:
        sock.connect((host, port))
        # 构造标准HTTP GET请求
        request = (
            f"GET {path} HTTP/1.1\r\n"
            f"Host: {host}\r\n"
            f"Connection: close\r\n\r\n"
        )
        sock.send(request.encode("utf-8"))
        
        # 读取全部响应数据
        raw_response = b""
        while chunk := sock.recv(4096):
            raw_response += chunk
    finally:
        sock.close()
    
    # 转成字符串并处理编码异常
    response_str = raw_response.decode("utf-8", errors="ignore")
    
    # 定位第二个有效的HTTP头起始位置
    second_header_idx = response_str.find("HTTP/1.1")
    if second_header_idx == -1:
        # 兼容处理:如果没找到HTTP/1.1, fallback到第一个HTTP开头
        second_header_idx = response_str.find("HTTP/")
    
    # 分割有效头部和正文
    header_section = response_str[second_header_idx:].split("\r\n\r\n")[0]
    set_cookies = []
    
    # 遍历头部行提取Set-Cookie
    for line in header_section.split("\r\n")[1:]:  # 跳过状态行(如HTTP/1.1 200 OK)
        line_lower = line.lower()
        if line_lower.startswith("set-cookie:"):
            cookie_val = line.split(":", 1)[1].strip()
            set_cookies.append(cookie_val)
    
    return set_cookies

# 调用示例
cookies = extract_set_cookies("10.0.0.10", "/cgi-bin/index")
print("获取到的Set-Cookie:", cookies)

这个方法的核心是直接读取设备返回的所有原始数据,手动定位到有效的HTTP头部分,然后提取Set-Cookie字段。因为完全自定义解析,所以能适配这种不符合规范的响应。

方案2:利用requests的raw流读取(可选)

如果你更习惯用requests,可以尝试开启流模式读取原始响应,不过需要注意urllib3可能还是会对响应做部分处理,可作为备选方案:

import requests

r = requests.get("http://10.0.0.10/cgi-bin/index", stream=True)
# 读取全部原始字节
raw_data = b""
for chunk in r.raw.stream(4096, decode_content=False):
    raw_data += chunk

# 后续处理逻辑和方案1一致
response_str = raw_data.decode("utf-8", errors="ignore")
second_header_idx = response_str.find("HTTP/1.1")
if second_header_idx != -1:
    header_section = response_str[second_header_idx:].split("\r\n\r\n")[0]
    set_cookies = [
        line.split(":",1)[1].strip()
        for line in header_section.split("\r\n")[1:]
        if line.lower().startswith("set-cookie:")
    ]
    print("Set-Cookie:", set_cookies)

注意事项

  • 这种双重HTTP头是不符合RFC规范的,本质是IoT设备的服务器端bug,如果条件允许,建议联系设备厂商修复这个问题。
  • 处理原始响应时务必设置超时,避免因为设备响应缓慢导致程序卡住。
  • 如果设备使用HTTPS(端口443),可以用ssl.wrap_socket对socket进行加密包装,或者改用requests的流模式+SSL,处理逻辑类似。

内容的提问来源于stack exchange,提问作者Aku O

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 07:00:02