reqwest_proxy 0.1.3

A reqwest middleware for proxying requests through shadowsocks, hysteria2, and other proxies. 一个通过 shadowsocks, hysteria2 等代理服务器代理请求的 reqwest 中间件。
Documentation

reqwest_proxy

English | 中文


English

Table of Contents

Project Significance

In an increasingly connected world, developers often face challenges with network restrictions and censorship. For applications requiring reliable access to global resources, routing traffic through a proxy is not just a convenience but a necessity. This project, reqwest_proxy, provides a powerful and elegant solution for the Rust ecosystem.

It offers a drop-in reqwest middleware that enables applications to seamlessly route HTTP/HTTPS requests through various proxy inits. By abstracting the complexities of proxy connections, it empowers developers to build resilient, censorship-resistant applications with minimal effort, making reqwest an even more versatile tool for global connectivity.

Features

  • Multi-Protocol Support: Out-of-the-box support for modern proxy inits, including Shadowsocks and Hysteria2.
  • Seamless Integration: Designed as a reqwest-middleware component for easy integration into existing projects.
  • Unified API: A single, intuitive entry point (Proxy::from_url) to configure different proxy types.
  • Asynchronous by Design: Built on tokio for high-performance, non-blocking I/O.
  • Resilient and Robust: Leverages mature underlying libraries like shadowsocks-rust for stable and efficient connections.

Design Philosophy

The core design principle is abstraction and simplicity. The library aims to provide a unified interface for various proxy inits, hiding the implementation details of each one.

The central component is the Proxy enum, which acts as the middleware. The call flow is straightforward:

  1. The user provides a proxy server URL (e.g., ss://... or hysteria2://...).
  2. The Proxy::from_url async function parses the URL, determines the init, and initializes the appropriate underlying client connector.
  3. This Proxy instance is then attached to the reqwest_middleware::ClientBuilder.
  4. When a request is sent, the middleware intercepts it, converts it into a hyper::Request, and sends it through a hyper::Client configured to use the selected proxy connector. This establishes a connection to the destination through the proxy server, transparently piping the data.

This design ensures that developers can switch between different proxy inits without changing their application logic, simply by modifying the configuration URL.

Usage

Here is a practical example of how to integrate reqwest_proxy with reqwest_middleware::ClientBuilder.

First, ensure you have enabled the desired init features in your Cargo.toml:

[dependencies]
reqwest_proxy = { version = "0.1", features = ["full"] }

Then, use the Proxy middleware in your application:

use anyhow::Result;
use reqwest_middleware::{ClientBuilder, ClientWithMiddleware};
use reqwest_proxy::Proxy;

#[tokio::main]
async fn main() -> Result<()> {
    // 1. Define your proxy server URL.
    //    This example uses Shadowsocks, but Hysteria2 is also supported.
    //    Replace with your actual server details.
    let proxy_url = "ss://aes-256-gcm:password@your-server-address:port";

    // 2. Create an instance of the Proxy middleware from the URL.
    let proxy_middleware = Proxy::from_url(proxy_url).await?;

    // 3. Build a reqwest client and attach the middleware.
    //    It's good practice to disable the system proxy to ensure
    //    traffic goes exclusively through the specified proxy.
    let client: ClientWithMiddleware = ClientBuilder::new(
        reqwest::Client::builder().no_proxy().build()?
    ).with(proxy_middleware).build();

    // 4. Use the client to send requests as you normally would.
    //    The traffic will be automatically proxied.
    let test_url = "https://ifconfig.me/ip";
    match client.get(test_url).send().await {
        Ok(res) => {
            let status = res.status();
            let ip = res.text().await?;
            // The IP printed should be that of your proxy server.
            println!("Request to {test_url}: Status={status}, IP={ip}");
        }
        Err(e) => {
            eprintln!("Request to {test_url} failed: {e}");
        }
    }

    Ok(())
}

Tech Stack

  • reqwest: An ergonomic, batteries-included HTTP client for Rust.
  • reqwest-middleware: The framework for creating and chaining middleware for reqwest.
  • tokio: The de facto asynchronous runtime for network applications in Rust.
  • hyper: A low-level, high-performance HTTP library that powers reqwest.
  • shadowsocks-rust: A robust and efficient Rust implementation of the Shadowsocks init.
  • hysteria2: The core library for the Hysteria2 init, known for its high speed and congestion control.
  • thiserror: For creating structured and descriptive error types.

File Structure

The src directory is organized to promote modularity and feature-based compilation:

src
├── error.rs       # Defines custom error types for the library using `thiserror`.
├── hysteria2.rs   # Implements the Hysteria2 init connector.
├── lib.rs         # The main library entry point. Uses macros and feature flags to assemble the final public API.
├── macro_conn.rs  # A macro to reduce boilerplate for connection future types.
├── macro_enums.rs # A powerful macro that generates the core enums (`Proxy`, `ProxyConn`, `StreamEnum`) which unify the different inits.
├── middleware.rs  # Contains the primary `ProxyMiddleware` logic that integrates with `reqwest-middleware`.
├── shadowsocks.rs # Implements the Shadowsocks init connector.
├── stream.rs      # Provides a unified `Stream` wrapper over different proxy connection types for `hyper`.
├── traits.rs      # Defines the common `Conn` and `StreamTrait` traits that each init implementation must adhere to.
└── util.rs        # Utility functions, such as for handling `hyper` bodies.

A Little Story

The story of proxy inits is one of a constant cat-and-mouse game. It began with simple inits, but as network surveillance evolved, so did the need for obfuscation.

Shadowsocks, created in 2012 by a Chinese programmer known as "clowwindy," was a breakthrough. Its innovation was a lightweight, encrypted init designed to be indistinguishable from regular HTTPS traffic, making it difficult for automated firewalls to detect and block. Its open-source nature allowed a global community to carry it forward even after the original author ceased development under pressure, ensuring its survival and evolution.

More recently, inits like Hysteria2 have emerged, pushing the boundaries further. Built on top of QUIC (the transport init for HTTP/3), it focuses on maximizing throughput and minimizing latency, even in challenging network conditions with high packet loss. It can masquerade as standard HTTP/3 traffic, making it exceptionally difficult to block without causing collateral damage. The evolution from Shadowsocks to Hysteria2 showcases the relentless innovation in the pursuit of an open and unrestricted internet—a shift from simple obfuscation to sophisticated performance engineering.


中文

目录

项目意义

在日益互联的世界中,开发者常常面临网络限制和审查的挑战。对于需要可靠访问全球资源的应用程序来说,通过代理路由流量不仅是为了方便,更是一种必需。本项目 reqwest_proxy 为 Rust 生态系统提供了一个强大而优雅的解决方案。

它提供了一个即插即用的 reqwest 中间件,使应用程序能够无缝地通过各种代理协议路由 HTTP/HTTPS 请求。通过抽象代理连接的复杂性,它使开发者能够以最小的努力构建具有弹性、抗审查能力的应用程序,使 reqwest 成为一个功能更强大的全球连接工具。

功能特性

  • 多协议支持: 开箱即用地支持现代代理协议,包括 ShadowsocksHysteria2
  • 无缝集成: 设计为 reqwest-middleware 组件,可轻松集成到现有项目中。
  • 统一的 API: 单一、直观的入口点 (Proxy::from_url),用于配置不同的代理类型。
  • 原生异步: 基于 tokio 构建,实现高性能、非阻塞的 I/O。
  • 稳定与健壮: 依赖 shadowsocks-rust 等成熟的底层库,确保连接稳定高效。

设计思路

核心设计原则是抽象与简洁。该库旨在为各种代理协议提供统一的接口,隐藏每种协议的实现细节。

核心组件是 Proxy 枚举,它充当中间件。调用流程非常直接:

  1. 用户提供一个代理服务器 URL (例如 ss://...hysteria2://...)。
  2. Proxy::from_url 异步函数解析该 URL,确定协议类型,并初始化相应的底层客户端连接器。
  3. 这个 Proxy 实例随后被附加到 reqwest_middleware::ClientBuilder 上。
  4. 当发送请求时,中间件会拦截它,将其转换为 hyper::Request,并通过一个配置了所选代理连接器的 hyper::Client 发送。这样就通过代理服务器建立到目标的连接,并透明地传输数据。

这种设计确保了开发者只需修改配置 URL,就可以在不同的代理协议之间切换,而无需更改其应用程序逻辑。

使用演示

这是一个如何将 reqwest_proxyreqwest_middleware::ClientBuilder 集成的实用示例。

首先,请确保您已在 Cargo.toml 中启用了所需的协议功能:

[dependencies]
reqwest_proxy = { version = "0.1", features = ["full"] }

然后,在您的应用程序中使用 Proxy 中间件:

use anyhow::Result;
use reqwest_middleware::{ClientBuilder, ClientWithMiddleware};
use reqwest_proxy::Proxy;

#[tokio::main]
async fn main() -> Result<()> {
    // 1. 定义您的代理服务器 URL。
    //    此示例使用 Shadowsocks,但也支持 Hysteria2。
    //    请替换为您的实际服务器信息。
    let proxy_url = "ss://aes-256-gcm:password@your-server-address:port";

    // 2. 从 URL 创建一个 Proxy 中间件实例。
    let proxy_middleware = Proxy::from_url(proxy_url).await?;

    // 3. 构建一个 reqwest 客户端并附加中间件。
    //    禁用系统代理是一个好习惯,以确保流量完全通过指定的代理。
    let client: ClientWithMiddleware = ClientBuilder::new(
        reqwest::Client::builder().no_proxy().build()?
    ).with(proxy_middleware).build();

    // 4. 像平常一样使用客户端发送请求。
    //    流量将被自动代理。
    let test_url = "https://ifconfig.me/ip";
    match client.get(test_url).send().await {
        Ok(res) => {
            let status = res.status();
            let ip = res.text().await?;
            // 打印出的 IP 应该是您的代理服务器的 IP。
            println!("请求 {test_url}: Status={status}, IP={ip}");
        }
        Err(e) => {
            eprintln!("请求 {test_url} 失败: {e}");
        }
    }

    Ok(())
}

技术栈

  • reqwest: 一个符合人体工程学、功能完备的 Rust HTTP 客户端。
  • reqwest-middleware: 用于为 reqwest 创建和链接中间件的框架。
  • tokio: Rust 网络应用程序事实上的标准异步运行时。
  • hyper: 一个为 reqwest 提供支持的底层、高性能 HTTP 库。
  • shadowsocks-rust: 一个健壮且高效的 Shadowsocks 协议 Rust 实现。
  • hysteria2: Hysteria2 协议的核心库,以其高速度和拥塞控制而闻名。
  • thiserror: 用于创建结构化和描述性强的错误类型。

文件结构

src 目录的组织方式旨在促进模块化和基于特性的编译:

src
├── error.rs       # 使用 `thiserror` 为库定义自定义错误类型。
├── hysteria2.rs   # 实现 Hysteria2 协议的连接器。
├── lib.rs         # 主库入口点。使用宏和特性标志来组装最终的公共 API。
├── macro_conn.rs  # 一个用于减少连接 Future 类型的样板代码的宏。
├── macro_enums.rs # 一个强大的宏,用于生成统一不同协议的核心枚举(`Proxy`、`ProxyConn`、`StreamEnum`)。
├── middleware.rs  # 包含与 `reqwest-middleware` 集成的主要 `ProxyMiddleware` 逻辑。
├── shadowsocks.rs # 实现 Shadowsocks 协议的连接器。
├── stream.rs      # 为 `hyper` 提供一个统一的 `Stream` 包装器,用于处理不同的代理连接类型。
├── traits.rs      # 定义每个协议实现必须遵守的通用 `Conn` 和 `StreamTrait` trait。
└── util.rs        # 工具函数,例如用于处理 `hyper` 的 body。

相关故事

代理协议的故事是一场持续的猫鼠游戏。它始于简单的协议,但随着网络审查技术的发展,混淆流量的需求也随之演进。

Shadowsocks,由中国程序员 "clowwindy" 于 2012 年创建,是一个突破。其创新之处在于一种轻量级的加密协议,其流量特征旨在与普通 HTTPS 流量无法区分,使自动化防火墙难以检测和阻止。其开源的特性使得一个全球性的社区能够在原作者因压力停止开发后继续推动其发展,确保了它的生存和演进。

最近,像 Hysteria2 这样的协议应运而生,将技术推向了新的高度。它构建于 QUIC(HTTP/3 的传输协议)之上,专注于即使在具有高丢包率的挑战性网络条件下也能最大化吞ut量和最小化延迟。它可以伪装成标准的 HTTP/3 流量,使得在不造成附带损害的情况下极难被封锁。从 Shadowsocks 到 Hysteria2 的演进,展示了在追求开放和无限制互联网过程中的不懈创新——这是一场从简单混淆到复杂性能工程的转变。

About

This project is an open-source component of i18n.site ⋅ Internationalization Solution.

关于

本项目为 i18n.site ⋅ 国际化解决方案 的开源组件。