Ngiêm cấm sử đụng PROXY và VPS vào mục đích trái pháp luật bạn sẽ phải chịu toàn bộ trách nhiệm trước pháp luật khi sử dụng dịch vụ của chúng tôi tks!
Rust ureq proxy: cấu hình Proxy cho Agent ureq 3 và SOCKS5

Rust ureq proxy: cấu hình Proxy cho Agent ureq 3 và SOCKS5

Chuyên viên Kỹ thuật ProxyVN 07-28-2026 Đang tính... phút đọc

Rust ureq proxy là cách cho thư viện HTTP đồng bộ ureq gửi request qua máy trung gian. ureq không cần tokio hay runtime bất đồng bộ, nên hợp với công cụ dòng lệnh và script Rust nhỏ gọn. Proxy được đặt trên Agent, mọi request qua Agent đều đi proxy. ProxyVN đối chiếu tài liệu ureq 3.5.0 để viết cấu hình, các ca lỗi và cách kiểm đường đi.

Rust ureq proxy khác reqwest ở điểm nào

ureq là client đồng bộ

ureq là thư viện HTTP viết bằng Rust thuần, chạy đồng bộ: gọi hàm, chờ, nhận kết quả. Không có async, không cần tokio, không kéo theo cả hệ sinh thái runtime. Với công cụ dòng lệnh, tác vụ cron hay chương trình nhỏ chỉ gọi vài API, ureq gọn và biên dịch nhanh hơn nhiều so với client bất đồng bộ.

Bài Rust reqwest proxy nói về reqwest, client bất đồng bộ phổ biến nhất. Bài Rust proxy nói về proxy trong Rust ở mức chung. Bài này chỉ đi vào API của ureq 3: kiểu Proxy, cách gắn vào cấu hình Agent, tính năng socks-proxy, timeout và kiểu lỗi.

ureq 3 thay đổi API đáng kể so với ureq 2. Ví dụ ureq 2 trên mạng như AgentBuilder::new().proxy(...) không biên dịch với bản 3. Kiểm số phiên bản trong Cargo.toml trước khi chép mã.

Proxy đặt trên Agent

Proxy đặt trên Agent

Proxy đặt trên Agent

Theo tài liệu ureq trên docs.rs, proxy được đặt trên Agent và mọi request gửi qua Agent đó đều được chuyển qua proxy. Không có tùy chọn proxy cho từng request. Muốn hai tuyến mạng, tạo hai Agent.

Agent giữ bể kết nối để dùng lại, và bản sao của Agent dùng chung trạng thái. Vì vậy tạo Agent một lần rồi truyền bản sao cho các luồng, không tạo Agent mới cho mỗi request.

Phạm vi kiểm thử

Máy lab của ProxyVN hôm viết bài không có cargo hay rustc, nên mã trong bài chưa được biên dịch và chạy trên máy này. Mình viết theo tài liệu ureq 3.5.0 trên docs.rs, bản phát hành ngày 21/10/2026 theo trang đó. Các đoạn mã giữ đúng tên kiểu và phương thức xuất hiện trong tài liệu.

Cuối bài có bộ ca kiểm với proxy cục bộ để anh em tự chạy. Nếu bản ureq của anh em khác 3.5, đối chiếu lại tài liệu đúng bản trên docs.rs.

Chuẩn bị project cho Rust ureq proxy

Cargo.toml và tính năng

Tài liệu ghi tính năng mặc định của ureq 3.5 là rustls và gzip. Proxy HTTP hoạt động với tính năng mặc định. Proxy SOCKS4, SOCKS4A và SOCKS5 cần bật tính năng socks-proxy. Đọc và gửi JSON cần tính năng json.

[dependencies]
ureq = { version = "3.5", features = ["socks-proxy", "json"] }
serde = { version = "1", features = ["derive"] }

Khóa phiên bản lớn bằng "3.5" để cargo không nhảy sang bản lớn khác. Với dự án cần tái tạo bản dựng chính xác, commit cả Cargo.lock.

Chọn thư viện TLS

Mặc định ureq dùng rustls. Tài liệu có tính năng native-tls cho người cần dùng thư viện TLS của hệ điều hành, và ghi rõ native-tls không bao giờ là mặc định, phải đặt trên Agent. Với proxy HTTP kiểu CONNECT, chọn thư viện TLS chỉ ảnh hưởng tới kết nối tới website, không ảnh hưởng tới kết nối tới proxy.

Với proxy HTTPS, tức kết nối tới chính proxy bằng TLS, tài liệu ghi cần một bộ cung cấp TLS. Trong mạng công ty có CA nội bộ, có thể cần tính năng platform-verifier hoặc native-tls để tin CA trong kho hệ điều hành. Đây là chỗ hay gây lỗi chứng chỉ chỉ khi ở công ty.

Thông tin proxy trong biến môi trường

Không ghi tài khoản proxy trong mã nguồn hay trong tệp được commit. Đọc từ biến môi trường. Nếu nhà cung cấp gửi dạng ip:port:user:pass, đổi sang dạng URL. Bài định dạng proxy có bảng chuyển đổi.

Cấu hình Rust ureq proxy bằng Proxy::new

Định dạng URI proxy

Tài liệu kiểu Proxy của ureq ghi định dạng là giao thức, tên, mật khẩu, máy và cổng, trong đó mọi phần trừ máy đều có thể bỏ. Các ví dụ hợp lệ gồm http://127.0.0.1:8080, socks5://john:[email protected], john:[email protected]:8000 và localhost.

Tài liệu nhắc phải mã hóa phần trăm tài khoản, và dấu cộng được giữ nguyên là dấu cộng. Mật khẩu p@ss#2026 viết thành p%40ss%232026. Thiếu bước này, phần sau ký tự @ đầu tiên bị hiểu là tên máy.

Gắn Proxy vào Agent

Cách gắn theo tài liệu là tạo Proxy từ URL, truyền vào cấu hình Agent bằng proxy(Some(proxy)), rồi chuyển cấu hình thành Agent.

use std::time::Duration;
use ureq::{Agent, Proxy};
 
fn build_agent() -> Result<Agent, ureq::Error> {
    let url = std::env::var("PROXY_URL").expect("thieu PROXY_URL");
    let proxy = Proxy::new(&url)?;
    let config = Agent::config_builder()
        .proxy(Some(proxy))
        .timeout_connect(Some(Duration::from_secs(5)))
        .timeout_global(Some(Duration::from_secs(30)))
        .build();
    Ok(config.into())
}

PROXY_URL có dạng http://user:mật-khẩu-đã-mã-hóa@máy:cổng. Hàm trả lỗi nếu URL không hợp lệ, thay vì để chương trình chạy tiếp không proxy. Với chương trình dùng thật, đó là hành vi nên có.

Dựng Proxy bằng builder

Khi tài khoản đến từ nhiều biến riêng, ghép chuỗi rồi mã hóa dễ sai. Tài liệu có Proxy::builder nhận kiểu giao thức, với các phương thức host, port, username, password, resolve_target và build. Builder nhận tài khoản là giá trị riêng nên không cần tự mã hóa phần trăm.

use ureq::{Proxy, ProxyProtocol};
 
let proxy = Proxy::builder(ProxyProtocol::Socks5)
    .host(&std::env::var("PROXY_HOST").unwrap())
    .port(1080)
    .username(&std::env::var("PROXY_USER").unwrap())
    .password(&std::env::var("PROXY_PASS").unwrap())
    .build()?;

Chữ ký cụ thể của từng phương thức, ví dụ nhận &str hay String, anh em đối chiếu với trang ProxyBuilder của đúng bản. Mình chưa biên dịch đoạn này.

Rust ureq proxy đọc từ biến môi trường

Proxy::try_from_env

Tài liệu có Proxy::try_from_env, kiểm ALL_PROXY, HTTPS_PROXY và HTTP_PROXY theo thứ tự, có kiểm cả biến chữ thường. Hàm trả None nếu không có biến nào hoặc URI không hợp lệ. Điểm cuối cùng cần chú ý: URI sai không báo lỗi mà trả None, chương trình sẽ đi thẳng.

let mut builder = Agent::config_builder();
match Proxy::try_from_env() {
    Some(p) => builder = builder.proxy(Some(p)),
    None => eprintln!("Khong co proxy hop le trong bien moi truong, di thang"),
}
let agent: Agent = builder.build().into();

In một dòng cảnh báo khi không có proxy giúp nhận ra cấu hình sai sớm. Với chương trình bắt buộc đi proxy, thay dòng cảnh báo bằng thoát với mã lỗi.

ALL_PROXY đứng trước HTTPS_PROXY

ALL_PROXY đứng trước HTTPS_PROXY

ALL_PROXY đứng trước HTTPS_PROXY

Thứ tự ALL_PROXY, HTTPS_PROXY, HTTP_PROXY có hệ quả bất ngờ. Nếu máy đã đặt ALL_PROXY cho một công cụ khác, ví dụ trỏ tới một proxy SOCKS, ureq sẽ dùng nó dù anh em vừa đặt HTTPS_PROXY. Khi thấy request đi sai proxy, kiểm cả ba biến cùng bản chữ thường.

Một proxy cho cả http và https là cách ureq làm việc: proxy đọc được từ biến được dùng cho mọi request của Agent, không phân biệt theo giao thức của URL. Nếu cần hai proxy khác nhau cho http và https, tạo hai Agent.

NO_PROXY

try_from_env cũng đọc NO_PROXY để quyết định host nào đi thẳng. Tài liệu ghi hỗ trợ tên máy chính xác, hậu tố có ký tự đại diện, hậu tố có dấu chấm và giá trị khớp tất cả. Proxy có phương thức is_no_proxy nhận URI, trả true khi kết nối nên đi thẳng.

export NO_PROXY="localhost,127.0.0.1,.corp.example,*.internal"

Bài no_proxy là gì giải thích quy ước viết danh sách. Với ureq, nhớ rằng NO_PROXY chỉ có tác dụng khi proxy lấy từ try_from_env, hoặc khi Proxy được dựng với thông tin bỏ qua. Mình chưa kiểm Proxy::new có đọc NO_PROXY hay không.

Rust ureq proxy với SOCKS5

Bật tính năng socks-proxy

Proxy SOCKS4, SOCKS4A và SOCKS5 cần tính năng socks-proxy. Thiếu tính năng, URL socks5:// có thể không được chấp nhận hoặc không hoạt động. Tài liệu ánh xạ tiền tố socks5 và socks sang SOCKS5.

let agent: Agent = Agent::config_builder()
    .proxy(Some(Proxy::new("socks5://user1:p%40ss%232026@127.0.0.1:1080")?))
    .build()
    .into();

Tài liệu kiểu Proxy không liệt kê tiền tố socks5h. Nếu chép URL từ công cụ khác có socks5h://, đổi thành socks5:// và dùng resolve_target để quyết định nơi phân giải tên miền.

resolve_target và nơi phân giải tên miền

Tài liệu ghi resolve_target mặc định false cho mọi giao thức trừ SOCKS4. Giá trị false nghĩa là proxy phân giải tên miền đích, máy khách gửi nguyên tên cho proxy. SOCKS4 không hỗ trợ gửi tên miền nên mặc định true, máy khách tự phân giải.

Với SOCKS5 mặc định, tên miền được gửi cho proxy, không rò truy vấn DNS ra nhà mạng của máy chạy chương trình. Đây là mặc định an toàn. Chỉ đổi resolve_target thành true khi proxy không phân giải được tên, ví dụ proxy trong mạng nội bộ không có DNS ra ngoài. Bài DNS leak khi dùng proxy giải thích rủi ro rò DNS.

HTTP hay SOCKS5 cho ureq

ureq hỗ trợ cả hai tốt. Proxy HTTP dùng tính năng mặc định, không cần thêm phụ thuộc. SOCKS5 cần tính năng socks-proxy nhưng cho phép đi qua những proxy chỉ mở cổng SOCKS. Với gói proxy có cả hai cổng, mình chọn HTTP cho công cụ dòng lệnh nhỏ để giảm phụ thuộc. Bài proxy HTTP và SOCKS5 so sánh chi tiết.

Timeout khi đi qua Rust ureq proxy

Đặt timeout, đừng để treo

Đặt timeout, đừng để treo

Mặc định không có giới hạn

Tài liệu ghi mọi timeout của ureq mặc định là None, trừ timeout_await_100 mặc định một giây. None nghĩa là không giới hạn. Với proxy, đây là rủi ro: một proxy treo có thể giữ luồng mãi.

Các timeout gồm timeout_global cho toàn bộ thao tác kể cả redirect và thân response, timeout_per_call cho một lần trao đổi và đặt lại sau mỗi redirect, timeout_connect, timeout_resolve, timeout_send_request, timeout_send_body, timeout_recv_response, timeout_recv_body, timeout_per_read và timeout_per_write.

Gợi ý cho tuyến proxy

Mình đặt ba giá trị: timeout_connect 5 giây cho bước kết nối tới proxy, timeout_recv_response 20 giây cho bước chờ website trả tiêu đề qua proxy, timeout_global 60 giây làm chốt chặn cuối. Với tải tệp lớn, tăng timeout_global hoặc dùng timeout_per_read để chỉ cắt khi luồng dữ liệu đứng yên quá lâu.

let config = Agent::config_builder()
    .proxy(Proxy::try_from_env())
    .timeout_connect(Some(Duration::from_secs(5)))
    .timeout_recv_response(Some(Duration::from_secs(20)))
    .timeout_global(Some(Duration::from_secs(60)))
    .build();

Khi đi qua proxy, timeout_connect đo việc kết nối tới proxy. Nếu proxy chết hoặc sai cổng, lỗi sẽ đến trong 5 giây thay vì treo. Khi timeout xảy ra, tài liệu ghi ureq báo Error::Timeout.

Không có thử lại tự động

ureq không tự thử lại request theo kiểu nhiều client khác. Với lỗi mạng tạm thời qua proxy, tự viết vòng thử lại giới hạn số lần, có khoảng nghỉ tăng dần, chỉ cho GET hoặc thao tác an toàn khi gửi lại.

fn get_with_retry(agent: &Agent, url: &str) -> Result<String, ureq::Error> {
    let mut last = None;
    for attempt in 0..3 {
        match agent.get(url).call() {
            Ok(mut resp) => return resp.body_mut().read_to_string(),
            Err(ureq::Error::Timeout(_)) | Err(ureq::Error::Io(_)) => {
                std::thread::sleep(Duration::from_millis(500 * 2u64.pow(attempt)));
                last = Some(attempt);
            }
            Err(e) => return Err(e),
        }
    }
    panic!("het so lan thu {:?}", last)
}

Tên biến thể Error::Io trong đoạn trên là theo hiểu biết của mình về ureq, tài liệu trang chính chỉ nêu rõ StatusCode và Timeout. Đối chiếu enum Error của đúng bản trước khi dùng. Với POST tạo dữ liệu, không thử lại hoặc dùng khóa chống trùng phía máy chủ.

Đọc lỗi Rust ureq proxy

Error::StatusCode cho 4xx và 5xx

Tài liệu ghi mặc định mã 4xx và 5xx tạo Error::StatusCode(code). Có thể tắt bằng http_status_as_error trong cấu hình. Điều này nghĩa là với ureq mặc định, 403 từ website và 407 từ proxy đều có thể hiện thành lỗi có mã trạng thái.

Với proxy HTTP kiểu CONNECT, 407 trả cho lệnh CONNECT, trước khi request thật tới website. Cách ureq báo lỗi này, là StatusCode(407) hay một biến thể lỗi khác, mình chưa kiểm. Ghi log cả kiểu lỗi và thông điệp để nhận ra.

match agent.get("https://api.example.com/items").call() {
    Ok(mut resp) => println!("{}", resp.body_mut().read_to_string()?),
    Err(ureq::Error::StatusCode(407)) => eprintln!("Proxy tu choi tai khoan"),
    Err(ureq::Error::StatusCode(code)) => eprintln!("Website tra {code}"),
    Err(ureq::Error::Timeout(t)) => eprintln!("Qua han: {t:?}"),
    Err(e) => eprintln!("Loi khac: {e}"),
}

Bảng tra nhanh

Bảng dưới gom các tình huống thường gặp theo tài liệu và cách proxy hoạt động, chưa phải kết quả lab.

Bảng: Bảng tra nhanh

Hiện tượng

Thường do

Kiểm trước

Request đi thẳng, không lỗi

try_from_env trả None vì URI sai hoặc thiếu biến

In cảnh báo khi None

Đi sai proxy

ALL_PROXY đang có giá trị

Kiểm ALL_PROXY, HTTPS_PROXY, HTTP_PROXY

Tên máy lạ trong lỗi kết nối

Mật khẩu chưa mã hóa phần trăm

Mã hóa @, #, :, /

socks5:// không hoạt động

Thiếu tính năng socks-proxy

Cargo.toml

Treo lâu khi proxy chết

Không đặt timeout

timeout_connect, timeout_global

Lỗi có mã 407

Proxy từ chối tài khoản

Tên, mật khẩu, IP cho phép

Lỗi có mã 403, 429

Website từ chối

IP, tần suất, tiêu đề

Khi gặp 407 cụ thể, bài sửa lỗi 407 Proxy Authentication Required có danh sách nguyên nhân phía nhà cung cấp.

Với ureq, Proxy::try_from_env trả None khi URI sai thay vì báo lỗi. Luôn kiểm giá trị trả về, nếu không chương trình sẽ lặng lẽ đi thẳng.

Gọi JSON qua Rust ureq proxy

send_json và read_json

Với tính năng json, tài liệu ghi gửi giá trị tuần tự hóa được bằng send_json và đọc response bằng body_mut().read_json. Proxy không ảnh hưởng tới cách gọi, vì nó nằm ở Agent.

use serde::{Deserialize, Serialize};
 
#[derive(Serialize)]
struct NewOrder<'a> { sku: &'a str, qty: u32 }
 
#[derive(Deserialize, Debug)]
struct Created { id: u64 }
 
let created: Created = agent
    .post("https://api.example.com/orders")
    .send_json(&NewOrder { sku: "A1", qty: 2 })?
    .body_mut()
    .read_json()?;
println!("{created:?}");

Khi website hoặc proxy trả trang HTML lỗi thay vì JSON, read_json báo lỗi giải mã. Đó là dấu hiệu nên đọc thân response thô bằng read_to_string để xem trang lỗi nói gì.

Tiêu đề và User-Agent

Proxy chỉ đổi IP nguồn. ureq gửi User-Agent riêng của thư viện, website nhận ra rất dễ. Đặt tiêu đề phù hợp bằng phương thức header trên request, hoặc đặt mặc định trong cấu hình Agent nếu bản ureq hỗ trợ. Với website có cơ chế chống bot, đổi IP mà giữ User-Agent của thư viện thường không giúp gì.

Với website cần cookie phiên, bật tính năng cookies để Agent giữ cookie giữa các request. Khi dùng proxy xoay đổi IP giữa phiên, cookie gắn với IP cũ có thể làm website nghi ngờ.

Rust ureq proxy trong công cụ dòng lệnh

Cho người dùng chọn proxy bằng cờ

Công cụ dòng lệnh viết bằng ureq thường chạy trên nhiều máy khác nhau: máy cá nhân, máy chủ CI, máy trong mạng công ty. Mỗi nơi có cách ra Internet riêng. Cách thân thiện nhất là cho người dùng ba lựa chọn theo thứ tự ưu tiên: cờ --proxy trên dòng lệnh, biến môi trường, rồi đi thẳng.

Thứ tự này giúp người dùng ghi đè cấu hình máy khi cần, ví dụ thử một proxy khác mà không đổi biến môi trường của cả phiên. Nó cũng giúp ghi log rõ ràng: công cụ biết proxy đến từ đâu và in ra nguồn đó.

fn pick_proxy(flag: Option<String>) -> Result<Option<ureq::Proxy>, ureq::Error> {
    if let Some(url) = flag {
        eprintln!("Dung proxy tu co --proxy");
        return Ok(Some(ureq::Proxy::new(&url)?));
    }
    if let Some(p) = ureq::Proxy::try_from_env() {
        eprintln!("Dung proxy tu bien moi truong");
        return Ok(Some(p));
    }
    eprintln!("Khong co proxy, di thang");
    Ok(None)
}

Khi cờ --proxy có URL sai, Proxy::new trả lỗi và công cụ dừng với thông báo rõ ràng. Đây là hành vi tốt hơn try_from_env, vốn trả None khi URI sai. Người dùng gõ nhầm cờ sẽ biết ngay, không phải đoán vì sao request đi thẳng.

Không in mật khẩu ra màn hình

Thông báo nguồn proxy chỉ nên nói nguồn, không in URL. URL proxy có thể chứa tài khoản, và log của công cụ dòng lệnh thường bị dán vào ticket hay chat nhóm khi gỡ lỗi. Nếu cần in, cắt phần tài khoản trước ký tự @ cuối cùng.

Cờ trên dòng lệnh cũng có rủi ro riêng: nó nằm trong lịch sử lệnh của shell và có thể hiện trong danh sách tiến trình trên máy dùng chung. Với máy chủ dùng chung, khuyên người dùng đặt biến môi trường thay vì cờ.

Rust ureq proxy sau proxy kiểm tra TLS

Vì sao rustls không tin CA của công ty

Mặc định ureq dùng rustls với bộ chứng chỉ gốc riêng, không đọc kho chứng chỉ của hệ điều hành. Ở công ty có thiết bị giải mã HTTPS, chứng chỉ mà ureq nhận được do CA nội bộ ký. rustls không biết CA đó, kết nối báo lỗi chứng chỉ dù trình duyệt trên cùng máy chạy bình thường.

Triệu chứng này rất dễ bị đổ cho proxy. Thực ra proxy vẫn chuyển tiếp đúng, vấn đề nằm ở lòng tin chứng chỉ. Đổi proxy hay đổi tài khoản không sửa được.

platform-verifier hoặc native-tls

Tài liệu ureq liệt kê tính năng platform-verifier và native-tls. Theo tên gọi, platform-verifier dùng bộ kiểm chứng chỉ của nền tảng, còn native-tls dùng thư viện TLS của hệ điều hành, cả hai đều có thể đọc CA mà công ty đã cài vào máy. Bật một trong hai và cấu hình trên Agent theo hướng dẫn của đúng bản ureq.

Mình chưa thử cách nào trong lab. Nếu không muốn đổi thư viện TLS, có thể nạp tệp PEM của CA nội bộ vào cấu hình TLS của ureq, nếu bản đang dùng hỗ trợ. Đừng tắt kiểm tra chứng chỉ để chữa lỗi, vì làm vậy mở đường cho tấn công xen giữa.

Rust ureq proxy với nhiều luồng

Bản sao Agent dùng chung bể kết nối

Vì ureq đồng bộ, muốn gửi song song phải dùng nhiều luồng. Tài liệu ghi bản sao của Agent dùng chung trạng thái, nên cách làm là tạo một Agent, clone cho mỗi luồng. Các luồng dùng chung bể kết nối tới proxy, không tốn thêm bắt tay khi kết nối còn sống.

Giới hạn số luồng bằng hoặc thấp hơn hạn mức kết nối đồng thời của gói proxy. Vượt hạn mức, proxy có thể từ chối kết nối mới hoặc cắt kết nối đang chạy, trong log trông giống mạng chập chờn. Với vài chục luồng, một bể luồng cố định từ thư viện như rayon hoặc tự quản bằng std::thread là đủ.

Khi nào nên đổi sang client bất đồng bộ

Nếu cần hàng trăm hay hàng nghìn kết nối đồng thời qua proxy, mỗi kết nối một luồng hệ điều hành sẽ tốn bộ nhớ. Lúc đó client bất đồng bộ như reqwest trên tokio hợp hơn. Bài Rust reqwest proxy đã nhắc ở đầu có hướng dẫn cho trường hợp đó.

Với đa số công cụ dòng lệnh và tác vụ định kỳ, ureq với vài luồng là đủ nhanh. Đừng thêm runtime bất đồng bộ chỉ vì nghĩ nó nhanh hơn, khi nút thắt thật nằm ở hạn mức của proxy và website.

Chạy đối chứng Rust ureq proxy

Proxy cục bộ có nhật ký

Cách chắc nhất để kiểm cấu hình là cho Agent đi qua một proxy ghi nhật ký. Dùng mitmproxy ở chế độ thường, Squid, hoặc một proxy nhỏ tự viết. Proxy cần ghi phương thức, host đích, có tài khoản hay không, và với SOCKS là kiểu địa chỉ nhận được là tên miền hay IP.

Bộ ca kiểm tối thiểu

  • Agent không proxy: nhật ký trống, request đi thẳng.
  • Proxy::new với tài khoản đã mã hóa: nhật ký có CONNECT với tài khoản đúng.
  • Mật khẩu chưa mã hóa: lỗi kết nối tới tên máy lạ, hoặc Proxy::new báo lỗi.
  • try_from_env với URI sai: hàm trả None, chương trình in cảnh báo.
  • ALL_PROXY và HTTPS_PROXY cùng đặt: Agent dùng ALL_PROXY.
  • NO_PROXY chứa host đích: nhật ký không có dòng cho host đó.
  • SOCKS5 có tính năng socks-proxy: nhật ký SOCKS ghi kiểu địa chỉ là tên miền.
  • Proxy chết: lỗi trong khoảng timeout_connect.
  • Kiểm IP ra: gọi dịch vụ trả IP, so với IP proxy mong đợi.

Ca thứ năm giúp tránh bất ngờ trên máy chủ có sẵn ALL_PROXY. Ca thứ bảy xác nhận resolve_target mặc định đúng như tài liệu.

Kiểm IP ra trước khi chạy tác vụ

Trước tác vụ chính, gọi một dịch vụ trả IP công khai qua Agent có proxy, so với IP máy chủ. Nếu trùng, dừng chương trình với mã lỗi khác không. Ca này bắt được lỗi quên gắn proxy, try_from_env trả None hay ai đó xóa biến môi trường trên máy chủ.

let ip = agent.get("https://api.ipify.org").call()?.body_mut().read_to_string()?;
if Some(ip.trim()) == std::env::var("SERVER_PUBLIC_IP").ok().as_deref() {
    eprintln!("Request dang di thang, dung lai");
    std::process::exit(2);
}

Với proxy xoay, IP ra mỗi lần có thể khác, chỉ cần khác IP máy chủ. Ghi IP ra vào log mỗi lần chạy để đối chiếu khi website phản ánh truy cập bất thường.

Ghi kết quả

Ghi bản ureq, bản Rust, tính năng đã bật và kết quả từng ca. Mỗi lần nâng ureq, chạy lại. ureq 3 đã đổi API so với ureq 2, các bản nhỏ sau cũng có thể thay đổi hành vi biến môi trường hay timeout.

Đưa Rust ureq proxy vào dự án thật

Một Agent cho mỗi tuyến

Với công cụ gọi cả API bên ngoài và dịch vụ nội bộ, tạo hai Agent: một có proxy, một không. Truyền bản sao Agent cho các luồng. Bản sao dùng chung bể kết nối nên rẻ.

Với proxy xoay đổi IP theo tên người dùng, mỗi phiên cần một Agent với tài khoản riêng. Tạo Agent mới khi đổi phiên, Agent cũ tự giải phóng khi không còn tham chiếu.

Chọn loại proxy

ureq hay dùng trong công cụ dòng lệnh và tác vụ định kỳ gọi API. Với API yêu cầu IP cố định, proxy tĩnh phù hợp. Với lấy dữ liệu nhiều trang công khai, proxy xoay giúp chia tải. Với chương trình chạy trên máy chủ cố định, proxy xác thực theo IP giúp bỏ tài khoản khỏi URL.

ProxyVN có proxy dân cư tĩnh, datacenter và proxy xoay, hỗ trợ HTTP và SOCKS5, cấp tài khoản user và mật khẩu. Nếu cần proxy cho Agent ureq, anh em có thể mua proxy giá rẻ tại trang chủ ProxyVN rồi chạy bộ ca kiểm ở trên.

Giữ bí mật

Không in Proxy hay cấu hình Agent ra log nếu chúng có thể chứa tài khoản. Khi ghi log, chỉ ghi tên máy proxy, host đích, mã trạng thái và thời gian. Trên CI, đưa tài khoản proxy vào mục secret.

Câu hỏi thường gặp về Rust ureq proxy

ureq có đặt proxy cho từng request được không. Theo tài liệu, proxy đặt trên Agent và áp cho mọi request của Agent đó. Muốn tuyến khác, dùng Agent khác.

Mật khẩu có ký tự đặc biệt viết thế nào. Mã hóa phần trăm trong URL, hoặc dùng Proxy::builder với username, password riêng.

ureq có tự đọc HTTPS_PROXY không. Tài liệu mô tả Proxy::try_from_env đọc ALL_PROXY, HTTPS_PROXY, HTTP_PROXY. Mình khuyên gọi hàm này rõ ràng và kiểm giá trị None.

Có dùng được socks5h:// không. Tài liệu kiểu Proxy không liệt kê socks5h. Dùng socks5://, mặc định proxy phân giải tên miền.

Timeout mặc định bao nhiêu. Không có, trừ timeout_await_100 một giây. Phải tự đặt.

Mã ureq 2 có dùng được cho ureq 3 không. Không. API cấu hình Agent đã đổi, chép mã ureq 2 sẽ lỗi biên dịch.

ureq có hợp cho crawl lớn không. ureq đồng bộ, mỗi request chiếm một luồng. Với vài chục request song song, dùng bể luồng là đủ. Với hàng nghìn kết nối đồng thời, client bất đồng bộ như reqwest hợp hơn.

Proxy HTTPS khác proxy HTTP thế nào với ureq. Proxy HTTP nhận kết nối thường rồi mở đường hầm CONNECT. Proxy HTTPS yêu cầu chính kết nối tới proxy cũng dùng TLS, tài liệu ghi cần bộ cung cấp TLS. Đa số gói proxy thương mại dùng proxy HTTP, chỉ chọn https:// khi nhà cung cấp ghi rõ.

Dùng ureq trong WebAssembly có proxy không. ureq hướng tới chương trình chạy trên hệ điều hành có socket. Trong trình duyệt, request do trình duyệt điều khiển và proxy do trình duyệt quyết định.

Checklist Rust ureq proxy

Checklist Rust ureq proxy

Checklist Rust ureq proxy

Trước khi triển khai

  • ureq 3.x trong Cargo.toml, không chép mã ureq 2.
  • Bật socks-proxy nếu dùng SOCKS.
  • Mã hóa tài khoản trong URL hoặc dùng builder.
  • Kiểm None khi dùng try_from_env.
  • Kiểm ALL_PROXY trên máy chủ.
  • Đặt timeout_connect và timeout_global.
  • Xử lý Error::StatusCode tách 407 khỏi lỗi website.
  • Một Agent cho mỗi tuyến, dùng bản sao cho các luồng.

Giới hạn của bài

Mã chưa được biên dịch và chạy trên máy lab vì không có cargo. Bài theo tài liệu ureq 3.5.0 trên docs.rs. Một số chi tiết như biến thể Error::Io và chữ ký ProxyBuilder cần đối chiếu Rustdoc của đúng bản. Chưa thử proxy HTTPS, chưa thử native-tls hay platform-verifier sau proxy công ty.

Rust ureq proxy và những điều cần nhớ

Rust ureq proxy đặt trên Agent bằng proxy(Some(...)) trong cấu hình ureq 3. Mã hóa tài khoản, kiểm None khi đọc biến môi trường, coi chừng ALL_PROXY, bật socks-proxy cho SOCKS5 và luôn đặt timeout. Cần proxy ổn định cho Rust ureq proxy, liên hệ Proxy.vn - Nhà cung cấp dịch vụ proxy chất lượng hàng đầu Việt Nam.

TIN TỨC LIÊN QUAN