跳转至

客户端配置

x-api-rs 是 SDK,HTTP/性能/可用性相关参数都通过 RquestClientBuilder 暴露给上层使用方。 本文档列出所有可配置项的默认值、风险、何时该改。


设计原则

  • 安全默认 + 可覆盖:默认值对非幂等写操作(DM/Posts/Like/上传)安全,高级用户可通过 builder 覆盖
  • 协议常量不暴露:与 Twitter API 协议绑定的常量(如 MAX_MESSAGE_LENGTH = 10000、GraphQL queryId、Bearer Token)写死在 SDK 内,不可配置
  • 传输/性能参数暴露:timeout、retry、proxy、pool size、JA3 指纹等可调

配置项参考

http2_max_retry_count: usize 🔴

HTTP/2 自动重试次数。控制 rquest 在收到 RST_STREAM(REFUSED_STREAM)GOAWAY(NO_ERROR) 时是否自动重发请求。

项目
本 SDK 默认 0(禁用)
rquest 原始默认 2
风险等级 🔴 高(影响数据正确性)

为什么默认禁用

rquest 把 H2 REFUSED_STREAM 视为"请求未到达 server"自动重发(RFC 9113 §8.7-3.2)。 但 Twitter 在限流时会先处理请求再发 RST_STREAM——server 已经收到并执行了请求, rquest 仍重发,导致同一条 DM/Tweet 被发送 2 次。

200 并发 DM 场景实测:11-19 条消息出现重复(5.5%-9.5% 重复率)。

何时可以改成 >0

  • ✅ 客户端用于幂等读操作:搜索、获取用户资料、获取 timeline、获取私信列表
  • 绝对不能用于:DM 发送、发帖、点赞、转发、关注、上传——任何写操作

如果同一个客户端实例会混用读写,保留默认 0

用法

use x_api_rs::{RquestClientBuilder, CookieAuth, ClientTransaction};
use std::sync::Arc;

// ✅ 安全默认(推荐)
let client = RquestClientBuilder::new(auth, transaction).build()?;

// ⚠️ 仅在纯读场景下可考虑
let client = RquestClientBuilder::new(auth, transaction)
    .http2_max_retry_count(2)
    .build()?;

proxy_url: Option<String>

代理服务器 URL,支持 HTTP / HTTPS / SOCKS5。

项目
默认 None(直连)
风险等级 🟢 低

已知陷阱

  • Burp Suite 会破坏 JA3 指纹模拟(TLS MITM 终止连接)→ 触发 Twitter 226 反爬
  • 大文件 multipart 上传 (>~100KB) 通过 Burp 会失败:Stream failed to close correctly
  • 测试场景建议使用 mitmproxy 或直连

用法

RquestClientBuilder::new(auth, transaction)
    .proxy_url("http://127.0.0.1:8080".to_string())
    .build()?;

profile: Option<ClientProfile>

浏览器指纹 profile —— 把 TLS 指纹(JA3/JA4 + HTTP/2 SETTINGS)与 HTTP 头部(User-Agent / Sec-Ch-Ua)绑成一个自洽身份。支持每账号独立配置

项目
默认(不传) ClientProfile::Chrome { os: Windows, arch: X64 }(Chrome 136 Windows x64)
风险等级 🟢 低

为什么是一个参数而不是 enable_ja3 + fingerprint 两个:真实浏览器的 TLS 指纹和 HTTP 头是同一个身份,拆成两个独立开关会产生「UA 自称 Chrome 140、TLS 握手却是 Chrome 136」这种错配——而 UA/JA3 错配本身就是反爬识别机器人的特征。ClientProfile 保证两层永远一致。

默认为何固定 Chrome 136 Windows x64(而非随机):指纹模拟的目标是混进最大的真实人群,不是变独特。Chrome Windows 是全球 Twitter Web 桌面占比最大的配置,淹没在真人流量里最安全。随机化反而可能制造唯一性或 UA/JA3 错配。

跨账号差异化:要让 A 账号和 B 账号在 JA3 层真正不同,必须跨浏览器家族(Chrome / Safari / Firefox / Edge / OkHttp 各自 TLS 不同);在同一 Chrome 家族内换 OS/版本不改变 JA3。

支持的 profile

家族 构造 TLS 来源 HTTP 头
Chrome 136 ClientProfile::Chrome { os, arch } Emulation::Chrome136 SDK 自建完整 Sec-Ch-Ua-*
Safari macOS ClientProfile::SafariMac(v) rquest-util Safari emulation emulation 自带(Safari 不发 Sec-Ch-Ua)
Safari iOS ClientProfile::SafariIos(v) 同上 同上
Safari iPad ClientProfile::SafariIpad 同上 同上
Firefox ClientProfile::Firefox(v) rquest-util Firefox emulation 同上
Edge ClientProfile::Edge(v) rquest-util Edge emulation 同上
OkHttp(Android app) ClientProfile::OkHttp(v) rquest-util OkHttp emulation 同上
禁用 TLS 模拟(调试) ClientProfile::None rquest 默认 无模拟

HTTP/2:始终开启,h2 SETTINGS 帧指纹随 profile 一起模拟(ClientProfile::None 除外)。

TLS 版本锚定:Chrome 只锚定 136——这是 rquest-util 2.2.1 TLS emulation 的上限,也是唯一能保证 TLS 与 HTTP 头自洽的 Chrome 版本。不提供 137–144(其真实 JA3 未经库验证,会与 Chrome136 握手错配)。

Rust 用法

use x_api_rs::ClientProfile;
use x_api_rs::common::fingerprint::types::{OsType, Architecture};

// 默认(Chrome 136 Windows x64)
let client = Twitter::create(cookies, None, None).await?;

// 指定 Chrome macOS arm64
let p = ClientProfile::Chrome { os: OsType::MacOS, arch: Architecture::Arm64 };
let client = Twitter::create(cookies, None, Some(p)).await?;

// 查看当前身份
let info = client.fingerprint_info();
println!("{} {} {} {}", info.browser, info.version, info.platform, info.user_agent);

完整示例

use x_api_rs::{Twitter, ClientProfile};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let cookies = "ct0=xxx; auth_token=yyy; twid=u%3D123".to_string();

    // 默认安全配置(Chrome 136 Windows x64,启用 JA3,H2 重试禁用)
    let twitter = Twitter::create(cookies.clone(), None, None).await?;

    // 带代理 + 指定 profile
    use x_api_rs::common::fingerprint::types::{OsType, Architecture};
    let p = ClientProfile::Chrome { os: OsType::MacOS, arch: Architecture::Arm64 };
    let twitter = Twitter::create(cookies, Some("http://127.0.0.1:8080".into()), Some(p)).await?;

    Ok(())
}

需要细粒度控制 http2_max_retry_count 等传输参数时,用 RquestClientBuilder::new(auth, transaction).profile(...).http2_max_retry_count(0).build()? + Twitter::with_client(...)


Python 用户

from x_api_rs import Twitter, ClientProfile

# 默认(Chrome 136 Windows x64)
client = await Twitter.create(cookies)

# 带代理
client = await Twitter.create(cookies, proxy_url="http://127.0.0.1:8080")

# 每账号独立身份——跨家族才有真实 JA3 差异
a = await Twitter.create(cookies_a, profile=ClientProfile.chrome("macos", "arm64"))
b = await Twitter.create(cookies_b, profile=ClientProfile.safari_ios("18.1.1"))
c = await Twitter.create(cookies_c, profile=ClientProfile.okhttp("5"))

# 禁用 TLS 模拟(仅调试)
d = await Twitter.create(cookies, profile=ClientProfile.none())

# 查看实际身份
info = a.fingerprint_info()
print(info.browser, info.version, info.platform)
print(info.user_agent)

ClientProfile 工厂方法

方法 说明
ClientProfile.chrome(os, arch) Chrome 136。os: windows/macos/linux;arch: x64/arm64
ClientProfile.safari_mac(version) Safari macOS。17.5/18/18.2/18.3/18.3.1
ClientProfile.safari_ios(version) Safari iOS。17.4.1/18.1.1
ClientProfile.safari_ipad() Safari iPadOS 18
ClientProfile.firefox(version) Firefox。133/135/136/private136/android135
ClientProfile.edge(version) Edge。131/134
ClientProfile.okhttp(version) OkHttp(Android app)。5/4.12
ClientProfile.none() 禁用 TLS 模拟(调试)

fingerprint_info() 返回 ProfileInfo,字段:browser / version / platform / user_agent

http2_max_retry_count 当前未在 Python 层暴露——因为 Python 用户场景几乎都涉及写操作, 强制使用安全默认(0)。如需读专用客户端,请联系 issue 反馈。


历史

  • 2026-05-09:发现 rquest 默认 http2_max_retry_count=2 导致 DM 重复发送,本 SDK 默认改为 0,并通过 RquestClientBuilder::http2_max_retry_count 暴露为可配置(v1.0.15)