Python发送REST GET请求时如何指定客户端端口?
如何在Python Requests库中指定客户端端口发起GET请求
你说的完全没错——默认情况下,Python的socket客户端发起连接时,系统会从空闲的动态端口范围里随机分配一个源端口,requests库底层依赖socket实现HTTP请求,所以默认行为确实是这样的。
至于你问的能不能指定特定客户端端口,答案是肯定的!虽然这个需求不算常见,但在一些特殊场景(比如防火墙强制要求客户端从特定端口发起请求、网络调试需要固定源端口)下完全合理,下面我给你两种可行的实现方法:
方法一:自定义HTTP适配器(通用方案)
requests本身没有直接暴露指定源端口的参数,但它基于urllib3实现,我们可以通过自定义适配器来修改urllib3的连接池配置,从而指定源端口:
import requests from urllib3.poolmanager import PoolManager class SourcePortAdapter(requests.adapters.HTTPAdapter): def __init__(self, source_port, *args, **kwargs): self.source_port = source_port super().__init__(*args, **kwargs) def init_poolmanager(self, connections, maxsize, block=False): # 初始化连接池时,通过source_address指定源端口 self.poolmanager = PoolManager( num_pools=connections, maxsize=maxsize, block=block, source_address=('', self.source_port) # 空字符串表示自动选择本地IP,端口为指定值 ) # 使用示例 if __name__ == "__main__": # 创建会话并挂载自定义适配器 session = requests.Session() target_port = 12345 # 你想要使用的客户端端口 adapter = SourcePortAdapter(target_port) session.mount('http://', adapter) session.mount('https://', adapter) # 发起GET请求,此时会使用指定的12345端口作为源端口 response = session.get('https://example.com') print(f"请求状态码: {response.status_code}")
代码说明:
- 我们继承了requests的
HTTPAdapter,重写了init_poolmanager方法,在创建PoolManager时传入source_address参数 source_address的格式是(本地IP, 端口),空字符串表示让系统自动选择合适的本地IP,你也可以指定具体的网卡IP(比如('192.168.1.5', 12345))- 将适配器挂载到session后,所有通过该session发起的请求都会使用指定的源端口
方法二:手动绑定socket(灵活定制方案)
如果需要更精细的控制(比如绑定到特定网卡+端口),可以手动创建socket并绑定端口,再让requests使用这个socket:
import requests from socket import socket, AF_INET, SOCK_STREAM # 创建socket并绑定到指定的本地IP和端口 local_ip = '192.168.1.5' # 你的网卡IP local_port = 12345 # 指定的客户端端口 s = socket(AF_INET, SOCK_STREAM) s.bind((local_ip, local_port)) # 提前连接到目标服务器(以HTTPS为例,端口443) s.connect(('example.com', 443)) # 自定义适配器,让请求使用我们绑定好的socket class CustomSocketAdapter(requests.adapters.HTTPAdapter): def send(self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None): # 将请求的连接替换为我们已绑定的socket conn = self.poolmanager.connection_from_host('example.com', port=443) conn.sock = s request.connection = conn return super().send(request, stream, timeout, verify, cert, proxies) # 使用示例 session = requests.Session() adapter = CustomSocketAdapter() session.mount('https://example.com', adapter) response = session.get('https://example.com') print(f"请求状态码: {response.status_code}")
注意事项:
- 端口可用性:确保指定的端口没有被其他进程占用,否则会抛出
OSError: [Errno 98] Address already in use错误 - 端口范围:普通用户只能使用1024-65535之间的端口,1-1023是系统保留端口,需要root/管理员权限才能使用
- HTTPS兼容性:两种方法都支持HTTPS请求,因为urllib3会自动处理TLS握手,我们只是修改了底层socket的源端口
内容的提问来源于stack exchange,提问作者Jamboree
相关产品推荐
相关产品推荐

