fix: 上传与MediaPost链路增加直连和urllib兜底
This commit is contained in:
1 parent
ee64b02b9e
commit
2a063a08ed
2 files changed
+126
-10
No files matched your search
@@ -179,6 +179,44 @@ class AssetsUploadReverse:
|
||||
"AssetsUpload transient exception, mark as retryable: "
|
||||
f"{err_msg}"
|
||||
)
|
||||
# 部分 '"code"' 异常不会走到上面的降级分支,这里再强制兜底一次。
|
||||
try:
|
||||
response = await session.post(
|
||||
UPLOAD_API,
|
||||
headers=headers,
|
||||
json=payload,
|
||||
timeout=timeout,
|
||||
)
|
||||
if response.status_code == 200:
|
||||
logger.info(
|
||||
"AssetsUpload recovered by forced direct fallback after transient error"
|
||||
)
|
||||
return response
|
||||
except Exception as forced_direct_err:
|
||||
logger.warning(
|
||||
"AssetsUpload forced direct fallback failed, "
|
||||
f"error={forced_direct_err}"
|
||||
)
|
||||
|
||||
try:
|
||||
response = await AssetsUploadReverse._urllib_post(
|
||||
url=UPLOAD_API,
|
||||
headers=headers,
|
||||
payload=payload,
|
||||
timeout=timeout,
|
||||
proxy_url=proxy_url,
|
||||
)
|
||||
if response.status_code == 200:
|
||||
logger.info(
|
||||
"AssetsUpload recovered by forced urllib fallback after transient error"
|
||||
)
|
||||
return response
|
||||
except Exception as forced_urllib_err:
|
||||
logger.warning(
|
||||
"AssetsUpload forced urllib fallback failed, "
|
||||
f"error={forced_urllib_err}"
|
||||
)
|
||||
|
||||
raise UpstreamException(
|
||||
message=f"AssetsUpload transient failure: {err_msg}",
|
||||
details={"status": 403, "error": err_msg},
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
Reverse interface: media post create.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import json
|
||||
import urllib.request
|
||||
from dataclasses import dataclass
|
||||
from typing import Any
|
||||
from curl_cffi.requests import AsyncSession
|
||||
|
||||
@@ -16,6 +20,51 @@ MEDIA_POST_API = "https://grok.com/rest/media/post/create"
|
||||
class MediaPostReverse:
|
||||
"""/rest/media/post/create reverse interface."""
|
||||
|
||||
@dataclass
|
||||
class _SimpleResponse:
|
||||
status_code: int
|
||||
headers: dict[str, str]
|
||||
text: str
|
||||
|
||||
def json(self):
|
||||
return json.loads(self.text or "{}")
|
||||
|
||||
@staticmethod
|
||||
async def _urllib_post(
|
||||
url: str, headers: dict[str, str], payload: dict[str, Any], timeout: int, proxy_url: str
|
||||
) -> "MediaPostReverse._SimpleResponse":
|
||||
body = json.dumps(payload).encode("utf-8")
|
||||
opener = None
|
||||
if proxy_url:
|
||||
opener = urllib.request.build_opener(
|
||||
urllib.request.ProxyHandler({"http": proxy_url, "https": proxy_url})
|
||||
)
|
||||
req = urllib.request.Request(url=url, data=body, headers=headers, method="POST")
|
||||
|
||||
def _do_post():
|
||||
if opener is not None:
|
||||
with opener.open(req, timeout=timeout) as resp:
|
||||
status = int(getattr(resp, "status", 200) or 200)
|
||||
raw_headers = {
|
||||
str(k).lower(): str(v) for k, v in dict(resp.headers.items()).items()
|
||||
}
|
||||
text = resp.read().decode("utf-8", errors="replace")
|
||||
return status, raw_headers, text
|
||||
with urllib.request.urlopen(req, timeout=timeout) as resp:
|
||||
status = int(getattr(resp, "status", 200) or 200)
|
||||
raw_headers = {
|
||||
str(k).lower(): str(v) for k, v in dict(resp.headers.items()).items()
|
||||
}
|
||||
text = resp.read().decode("utf-8", errors="replace")
|
||||
return status, raw_headers, text
|
||||
|
||||
status, raw_headers, text = await asyncio.to_thread(_do_post)
|
||||
return MediaPostReverse._SimpleResponse(
|
||||
status_code=status,
|
||||
headers=raw_headers,
|
||||
text=text,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
async def request(
|
||||
session: AsyncSession,
|
||||
@@ -39,6 +88,7 @@ class MediaPostReverse:
|
||||
# Get proxies
|
||||
base_proxy = get_config("proxy.base_proxy_url")
|
||||
proxies = {"http": base_proxy, "https": base_proxy} if base_proxy else None
|
||||
proxy_url = base_proxy
|
||||
|
||||
# Build headers
|
||||
headers = build_headers(
|
||||
@@ -64,23 +114,51 @@ class MediaPostReverse:
|
||||
browser = get_config("proxy.browser")
|
||||
|
||||
async def _do_request():
|
||||
response = await session.post(
|
||||
MEDIA_POST_API,
|
||||
headers=headers,
|
||||
json=payload,
|
||||
timeout=timeout,
|
||||
proxies=proxies,
|
||||
impersonate=browser,
|
||||
)
|
||||
try:
|
||||
response = await session.post(
|
||||
MEDIA_POST_API,
|
||||
headers=headers,
|
||||
json=payload,
|
||||
timeout=timeout,
|
||||
proxies=proxies,
|
||||
impersonate=browser,
|
||||
)
|
||||
except Exception as first_err:
|
||||
logger.warning(
|
||||
"MediaPostReverse primary request failed, fallback direct: "
|
||||
f"error={first_err}"
|
||||
)
|
||||
try:
|
||||
response = await session.post(
|
||||
MEDIA_POST_API,
|
||||
headers=headers,
|
||||
json=payload,
|
||||
timeout=timeout,
|
||||
)
|
||||
except Exception as second_err:
|
||||
logger.warning(
|
||||
"MediaPostReverse direct curl request failed, "
|
||||
f"fallback urllib: error={second_err}"
|
||||
)
|
||||
response = await MediaPostReverse._urllib_post(
|
||||
url=MEDIA_POST_API,
|
||||
headers=headers,
|
||||
payload=payload,
|
||||
timeout=timeout,
|
||||
proxy_url=proxy_url,
|
||||
)
|
||||
|
||||
if response.status_code != 200:
|
||||
content = ""
|
||||
try:
|
||||
content = await response.text()
|
||||
content = (response.text or "").strip().replace("\n", " ")
|
||||
except Exception:
|
||||
pass
|
||||
if len(content) > 300:
|
||||
content = f"{content[:300]}...(len={len(content)})"
|
||||
logger.error(
|
||||
f"MediaPostReverse: Media post create failed, {response.status_code}",
|
||||
"MediaPostReverse: Media post create failed, "
|
||||
f"status={response.status_code}, body={content or '-'}",
|
||||
extra={"error_type": "UpstreamException"},
|
||||
)
|
||||
raise UpstreamException(
|
||||
|
||||
Reference in new issue
Block a user