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

Python编写代理服务器报getaddrinfo failed错误如何修复

报错原因

socket.gaierror: [Errno 11001] getaddrinfo failed是DNS解析失败错误,说明传入socket.gethostbyname()的域名字符串非法,核心是代码中URL解析、socket管理存在多处逻辑bug:

  • 端口定位逻辑错误:用url.find(':')查找端口分隔符时,会匹配到http:///https://协议头里的冒号,无法正确识别域名后的端口分隔位置。
  • 索引基准不统一:webserverpos是基于去掉协议头的urlweb计算的索引,但截取端口时用的是原始完整URL的索引,两个字符串长度差了协议头的长度,截取出来的端口、域名内容完全错位。
  • 域名截取未排除端口:当URL带自定义端口时,截取webserver的逻辑会把端口号也拼入域名,比如example.com:8080会被当成域名传入DNS解析,必然失败。
  • Socket对象管理错误:代码中未在每个处理线程中独立创建TCP socket对象,要么触发未定义变量错误,要么多线程复用同一个socket导致连接状态混乱。
  • 未兼容HTTPS代理逻辑:普通HTTP代理处理HTTPS请求需要走CONNECT隧道,现有逻辑直接按HTTP明文方式请求80端口,HTTPS场景完全无法工作。
  • 缺少连接关闭判断:外层循环没有客户端断开的跳出逻辑,连接关闭后会无限循环接收空数据触发异常。
修复方案

以下是可正常转发HTTP请求的修复后完整代码,修正了上述所有逻辑问题:

import socket
import threading

def handle_client(client, client_address):
    target_sock = None
    try:
        while True:
            req = client.recv(8192)
            if not req:
                break
            req_text = req.decode('utf-8', errors='ignore')
            first_line = req_text.split('\n')[0].strip()
            if not first_line:
                break
            method, url, _ = first_line.split(' ')
            # 解析协议头
            if url.startswith('http://'):
                url_content = url[7:]
                default_port = 80
            elif url.startswith('https://'):
                # 简易版本暂不支持HTTPS,需要支持可补充CONNECT隧道逻辑
                client.send(b'HTTP/1.1 501 Not Implemented\r\n\r\nHTTPS requires CONNECT tunnel support')
                break
            else:
                client.send(b'HTTP/1.1 400 Bad Request\r\n\r\nInvalid proxy request')
                break
            # 拆分域名部分和路径部分
            if '/' in url_content:
                host_part, path_part = url_content.split('/', 1)
                path = '/' + path_part
            else:
                host_part = url_content
                path = '/'
            # 拆分域名和端口
            if ':' in host_part:
                webserver, port_str = host_part.split(':', 1)
                port = int(port_str)
            else:
                webserver = host_part
                port = default_port
            # 每个请求独立创建目标连接
            target_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            target_sock.connect((webserver, port))
            # 重构请求,替换全路径为相对路径发送给目标服务
            new_first_line = f'{method} {path} HTTP/1.1\r\n'
            req_lines = req_text.split('\n')[1:]
            new_req_lines = []
            for line in req_lines:
                line = line.strip()
                if not line:
                    continue
                if line.lower().startswith('connection:'):
                    new_req_lines.append('Connection: close')
                else:
                    new_req_lines.append(line)
            new_req = new_first_line + '\r\n'.join(new_req_lines) + '\r\n\r\n'
            target_sock.send(new_req.encode('utf-8', errors='ignore'))
            # 双向透传响应数据
            while True:
                resp_data = target_sock.recv(8192)
                if not resp_data:
                    break
                client.send(resp_data)
            break
    except Exception as e:
        print(f'Handle connection {client_address} failed: {str(e)}')
    finally:
        if target_sock:
            target_sock.close()
        client.close()

def main():
    listen_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    listen_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    listen_sock.bind(('127.0.0.1', 8888))
    listen_sock.listen(128)
    print('Proxy server listening on 127.0.0.1:8888')
    while True:
        client, addr = listen_sock.accept()
        t = threading.Thread(target=handle_client, args=(client, addr), daemon=True)
        t.start()

if __name__ == '__main__':
    main()
测试与扩展说明
  • 测试时不要直接设置全局系统代理,先用curl命令验证功能:curl -x http://127.0.0.1:8888 http://example.com,确认可以正常返回网页内容后再配置系统代理。
  • 如果需要支持HTTPS请求,需要补充CONNECT隧道逻辑:收到客户端的CONNECT 目标域名:443 HTTP/1.1请求后,先和目标服务的对应端口建立TCP连接,返回HTTP/1.1 200 Connection Established\r\n\r\n响应,之后直接双向透传客户端和目标服务之间的TCP流量即可,不需要解密HTTPS内容。

内容的提问来源于stack exchange,提问作者Nicholas Picklas

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.03 07:39:29