使用Python-requests访问IoT设备时响应头为空,因存在双重响应头
遇到这种设备返回非法双重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
相关产品推荐
相关产品推荐

