查看: 112|回复: 3

Python urllib3 库 HTTP 请求实战指南:从 GET 到异常处理

[复制链接]
发表于 7 小时前 | 显示全部楼层 |阅读模式
Python 的 urllib3 是开发中非常实用的 HTTP 客户端库,相比内置 urllib 更简洁、连接池管理更优秀,requests 底层实际也依赖它。本文从基础用法到异常处理,覆盖日常接口调用的核心场景。

### 安装与连接池

首先安装库:
  1. pip install urllib3
复制代码

创建连接池对象,这是推荐的用法,内部维护 TCP 连接复用,避免每次新建连接的性能损失:
  1. import urllib3
  2. http = urllib3.PoolManager()
复制代码

### GET 请求

最基础的 GET 请求:
  1. resp = http.request('GET', 'https://httpbin.org/get')
  2. print(resp.status)  # 200
  3. print(resp.data)    # bytes 类型,需要用 decode('utf-8') 转换成字符串
  4. print(resp.headers) # 响应头字典
复制代码

如果需要携带 URL 参数,使用 fields 参数传递字典,urllib3 会自动处理编码和拼接:
  1. resp = http.request(
  2.     'GET',
  3.     'https://httpbin.org/get',
  4.     fields={'key': 'value', 'page': 1}
  5. )
复制代码

### POST 请求的三种常见场景

1. 表单提交(application/x-www-form-urlencoded)
  1. resp = http.request(
  2.     'POST',
  3.     'https://httpbin.org/post',
  4.     fields={'username': 'admin', 'password': '123456'}
  5. )
复制代码

2. JSON 提交(application/json)

需手动序列化 body 并设置 Content-Type 头:
  1. import json
  2. resp = http.request(
  3.     'POST',
  4.     'https://httpbin.org/post',
  5.     body=json.dumps({'username': 'admin'}),
  6.     headers={'Content-Type': 'application/json'}
  7. )
复制代码

3. 上传文件(multipart/form-data)

fields 中使用元组格式 (文件名, 文件对象, MIME 类型):
  1. with open('photo.jpg', 'rb') as f:
  2.     resp = http.request(
  3.         'POST',
  4.         'https://httpbin.org/post',
  5.         fields={'file': ('photo.jpg', f, 'image/jpeg')}
  6.     )
复制代码

### 自定义请求头

常见需求是添加 User-Agent 和 Authorization:
  1. resp = http.request(
  2.     'GET',
  3.     'https://api.example.com/data',
  4.     headers={
  5.         'User-Agent': 'my-app/1.0',
  6.         'Authorization': 'Bearer xxxxxxx'
  7.     }
  8. )
复制代码

User-Agent 必加,很多接口会据此判断是否拒绝请求。

### 超时设置

生产环境必须设置超时,避免请求挂死:
  1. # 整体超时 3 秒
  2. resp = http.request('GET', 'https://httpbin.org/delay/5', timeout=3.0)
  3. # 分别设置连接超时和读取超时
  4. resp = http.request('GET', 'https://example.com', timeout=(3.0, 10.0))
复制代码

超时后会抛出 urllib3.exceptions.TimeoutError。

### 异常处理与重试

结合 retries 参数和 try/except 保证程序健壮性:
  1. import urllib3
  2. from urllib3.exceptions import HTTPError, TimeoutError, MaxRetryError
  3. http = urllib3.PoolManager(retries=3)  # 自动重试 3 次
  4. try:
  5.     resp = http.request('GET', 'https://httpbin.org/status/500')
  6.     resp.raise_for_status()  # 非 2xx 抛出 HTTPError
  7. except TimeoutError:
  8.     print('请求超时')
  9. except HTTPError as e:
  10.     print(f'HTTP错误: {e.response.status}')
  11. except MaxRetryError:
  12.     print('重试次数耗尽')
复制代码

常用异常类型:TimeoutError(超时)、HTTPError(状态码错误)、MaxRetryError(重试用完仍失败)。

### 连接池复用(性能关键)

创建 PoolManager 时配置连接池参数,然后复用一个实例发送多个请求,避免每次新建:
  1. http = urllib3.PoolManager(
  2.     num_pools=10,   # 最大连接池数量
  3.     maxsize=10,     # 每个池最大连接数
  4.     retries=3,      # 自动重试次数
  5.     timeout=5.0
  6. )
  7. r1 = http.request('GET', 'https://api.example.com/users')
  8. r2 = http.request('GET', 'https://api.example.com/orders')
复制代码

### 完整实战示例:调用 REST API

以下是一个封装函数,支持 GET/POST,自动处理 JSON 和异常:
  1. import urllib3
  2. import json
  3. http = urllib3.PoolManager(timeout=10.0, retries=3)
  4. def call_api(endpoint, data=None, method='GET'):
  5.     url = f'https://api.example.com{endpoint}'
  6.     kwargs = {
  7.         'method': method,
  8.         'headers': {
  9.             'Content-Type': 'application/json',
  10.             'Authorization': 'Bearer your_token_here'
  11.         }
  12.     }
  13.     if data:
  14.         kwargs['body'] = json.dumps(data)
  15.     try:
  16.         resp = http.request(url, **kwargs)
  17.         resp.raise_for_status()
  18.         return resp.data.decode('utf-8')
  19.     except urllib3.exceptions.HTTPError as e:
  20.         print(f'API返回错误: {e.response.status} - {e.response.data}')
  21.         return None
  22.     except urllib3.exceptions.TimeoutError:
  23.         print('请求超时')
  24.         return None
  25. # 调用示例
  26. result = call_api('/users', data={'name': 'zhangsan'}, method='POST')
  27. print(result)
复制代码

### 速查表

| 场景 | 核心参数 |
|------|----------|
| GET 请求 | http.request('GET', url) |
| 带参数 GET | fields={'k': 'v'} |
| POST 表单 | fields={'k': 'v'} |
| POST JSON | body=json.dumps(data), headers={'Content-Type': 'application/json'} |
| 上传文件 | fields={'file': ('name', fp, 'type')} |
| 自定义头 | headers={'Key': 'Value'} |
| 超时 | timeout=3.0 或 (conn_timeout, read_timeout) |
| 自动重试 | PoolManager(retries=3) |

掌握以上内容,日常 HTTP 接口调用可轻松应对。urllib3 不花哨,但足够稳定可靠。
回复

使用道具 举报

发表于 7 小时前 | 显示全部楼层

Re: Python urllib3 库 HTTP 请求实战指南:从 GET 到异常处理

很实用的教程,感谢楼主分享。urllib3 的连接池复用和异常处理写得清楚,尤其超时和重试在生产中太重要了。有个小疑问:如果接口需要代理,比如在公司内网,urllib3 该怎么配置?期待后续能补充代理设置的部分。
回复 支持 反对

使用道具 举报

发表于 5 小时前 | 显示全部楼层

Re: Python urllib3 库 HTTP 请求实战指南:从 GET 到异常处理

非常感谢楼主的详细教程!之前一直直接使用 `requests`,确实很少关注底层实现,原来 `urllib3` 才是核心。你写的连接池复用和异常处理部分非常实用,尤其是 `retries` 和 `timeout` 组合使用能大大提升程序健壮性。 想请教一下:在实际项目中,你更倾向于直接使用 `urllib3` 还是继续用 `requests`?什么场景下推荐直接用 `urllib3` 呢?毕竟 `requests` 封装更简洁,但 `urllib3` 连接池控制更细粒度,有点纠结。
回复 支持 反对

使用道具 举报

发表于 2 小时前 | 显示全部楼层

Re: Python urllib3 库 HTTP 请求实战指南:从 GET 到异常处理

感谢分享,非常实用的教程!之前一直用 requests 库偷懒,对 urllib3 的底层细节了解不深,这篇从连接池到异常处理都讲得很清楚,特别是分别设置连接超时和读取超时那部分,之前没注意到可以传元组,直接省去很多麻烦。 另外提醒一下,完整实战示例的代码最后一行 `'Content-` 好像被截断了,是少了 `Type': 'application/json'}` 吗?另外想请教一下,多个线程共用同一个 `PoolManager` 实例是否安全?还是需要手动加锁或者每个线程独立建池?
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

指导单位

江苏省公安厅

江苏省通信管理局

浙江省台州刑侦支队

DEFCON GROUP 86025

Hacking Group 021A

旗下站点

态势感知中心

应急响应中心

红盟安全

联系我们

官方QQ群:112851260

官方邮箱:security#ihonker.org(#改成@)

官方核心成员

关注微信公众号

Archiver|手机版|小黑屋| ( 沪ICP备2021026908号 )

GMT+8, 2026-6-16 17:50 , Processed in 0.024610 second(s), 18 queries , Gzip On, Redis On.

Powered by ihonker.com

Copyright © 2015-现在.

  • 返回顶部