Skip to content

Commit e2dbf89

Browse files
committed
fix: replace requests with httpx for improved HTTP handling
1 parent b700fd2 commit e2dbf89

File tree

5 files changed

+44
-60
lines changed

5 files changed

+44
-60
lines changed

backend/requirements.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ idna==3.4
99
pydantic~=1.10
1010
PySocks==1.7.1
1111
qbittorrent-api==2023.9.53
12-
requests==2.31.0
12+
httpx[socks,http2]==0.27.0
1313
six==1.16.0
1414
sniffio==1.3.0
1515
soupsieve==2.4.1

backend/src/module/checker/checker.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import logging
22
from pathlib import Path
33

4-
import requests
4+
import httpx
55
from sqlalchemy import inspect
66

77
from module.conf import VERSION, settings
@@ -58,7 +58,7 @@ def check_downloader() -> bool:
5858
if "://" not in settings.downloader.host
5959
else f"{settings.downloader.host}"
6060
)
61-
response = requests.get(url, timeout=2)
61+
response = httpx.get(url, timeout=2)
6262
# if settings.downloader.type in response.text.lower():
6363
if (
6464
"qbittorrent" in response.text.lower()
@@ -71,10 +71,10 @@ def check_downloader() -> bool:
7171
return False
7272
else:
7373
return False
74-
except requests.exceptions.ReadTimeout:
74+
except httpx.ReadTimeout:
7575
logger.error("[Checker] Downloader connect timeout.")
7676
return False
77-
except requests.exceptions.ConnectionError:
77+
except httpx.ConnectError:
7878
logger.error("[Checker] Downloader connect failed.")
7979
return False
8080
except Exception as e:

backend/src/module/conf/log.py

+3
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,6 @@ def setup_logger(level: int = logging.INFO, reset: bool = False):
3232
logging.StreamHandler(),
3333
],
3434
)
35+
logging.getLogger("httpx").setLevel(logging.WARNING)
36+
logging.getLogger("httpcore").setLevel(logging.WARNING)
37+
logging.getLogger("hpack").setLevel(logging.WARNING)

backend/src/module/network/request_url.py

+34-53
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import socket
33
import time
44

5-
import requests
5+
import httpx
66
import socks
77

88
from module.conf import settings
@@ -13,40 +13,39 @@
1313
class RequestURL:
1414
def __init__(self):
1515
self.header = {"user-agent": "Mozilla/5.0", "Accept": "application/xml"}
16-
self._socks5_proxy = False
1716

1817
def get_url(self, url, retry=3):
1918
try_time = 0
2019
while True:
2120
try:
22-
req = self.session.get(url=url, headers=self.header, timeout=5)
23-
logger.debug(f"[Network] Successfully connected to {url}. Status: {req.status_code}")
24-
req.raise_for_status()
25-
return req
26-
except requests.RequestException:
21+
req = self.session.get(url=url)
2722
logger.debug(
28-
f"[Network] Cannot connect to {url}. Wait for 5 seconds."
23+
f"[Network] Successfully connected to {url}. Status: {req.status_code}"
2924
)
25+
req.raise_for_status()
26+
return req
27+
except httpx.RequestError:
28+
logger.debug(f"[Network] Cannot connect to {url}. Wait for 5 seconds.")
3029
try_time += 1
3130
if try_time >= retry:
3231
break
3332
time.sleep(5)
3433
except Exception as e:
3534
logger.debug(e)
3635
break
37-
logger.error(f"[Network] Unable to connect to {url}, Please check your network settings")
36+
logger.error(
37+
f"[Network] Unable to connect to {url}, Please check your network settings"
38+
)
3839
return None
3940

4041
def post_url(self, url: str, data: dict, retry=3):
4142
try_time = 0
4243
while True:
4344
try:
44-
req = self.session.post(
45-
url=url, headers=self.header, data=data, timeout=5
46-
)
45+
req = self.session.post(url=url, data=data)
4746
req.raise_for_status()
4847
return req
49-
except requests.RequestException:
48+
except httpx.RequestError:
5049
logger.warning(
5150
f"[Network] Cannot connect to {url}. Wait for 5 seconds."
5251
)
@@ -65,60 +64,42 @@ def check_url(self, url: str):
6564
if "://" not in url:
6665
url = f"http://{url}"
6766
try:
68-
req = requests.head(url=url, headers=self.header, timeout=5)
67+
req = httpx.head(url=url)
6968
req.raise_for_status()
7069
return True
71-
except requests.RequestException:
70+
except httpx.RequestError:
7271
logger.debug(f"[Network] Cannot connect to {url}.")
7372
return False
7473

7574
def post_form(self, url: str, data: dict, files):
7675
try:
77-
req = self.session.post(
78-
url=url, headers=self.header, data=data, files=files, timeout=5
79-
)
76+
req = self.session.post(url=url, data=data, files=files)
8077
req.raise_for_status()
8178
return req
82-
except requests.RequestException:
79+
except httpx.RequestError:
8380
logger.warning(f"[Network] Cannot connect to {url}.")
8481
return None
8582

8683
def __enter__(self):
87-
self.session = requests.Session()
88-
if settings.proxy.enable:
89-
if "http" in settings.proxy.type:
90-
if settings.proxy.username:
91-
username=settings.proxy.username
92-
password=settings.proxy.password
93-
url = f"http://{username}:{password}@{settings.proxy.host}:{settings.proxy.port}"
94-
self.session.proxies = {
95-
"http": url,
96-
"https": url,
97-
}
98-
else:
99-
url = f"http://{settings.proxy.host}:{settings.proxy.port}"
100-
self.session.proxies = {
101-
"http": url,
102-
"https": url,
103-
}
104-
elif settings.proxy.type == "socks5":
105-
self._socks5_proxy = True
106-
socks.set_default_proxy(
107-
socks.SOCKS5,
108-
addr=settings.proxy.host,
109-
port=settings.proxy.port,
110-
rdns=True,
111-
username=settings.proxy.username,
112-
password=settings.proxy.password,
113-
)
114-
socket.socket = socks.socksocket
115-
else:
116-
logger.error(f"[Network] Unsupported proxy type: {settings.proxy.type}")
84+
proxy = self._build_proxy_url() if settings.proxy.enable else None
85+
self.session = httpx.Client(
86+
headers=self.headers, http2=True, proxies=proxy, timeout=5
87+
)
11788
return self
11889

11990
def __exit__(self, exc_type, exc_val, exc_tb):
120-
if self._socks5_proxy:
121-
socks.set_default_proxy()
122-
socket.socket = socks.socksocket
123-
self._socks5_proxy = False
12491
self.session.close()
92+
93+
def _build_proxy_url(self):
94+
proxy_type = "http" if "http" in settings.proxy.type else "socks5h"
95+
auth = (
96+
f"{settings.proxy.username}:{settings.proxy.password}@"
97+
if settings.proxy.username
98+
else ""
99+
)
100+
101+
if proxy_type not in ["http", "socks5h"]:
102+
logger.error(f"[Network] Unsupported proxy type: {settings.proxy.type}")
103+
return None
104+
105+
return f"{proxy_type}://{auth}{settings.proxy.host}:{settings.proxy.port}"

backend/src/module/utils/json_config.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import json
22

3-
import requests
3+
import httpx
44

55

66
def load(filename):
@@ -15,5 +15,5 @@ def save(filename, obj):
1515

1616

1717
def get(url):
18-
req = requests.get(url)
18+
req = httpx.get(url)
1919
return req.json()

0 commit comments

Comments
 (0)