如何用Rust和Actix框架快速获取并显示访问者IP地址(适用于阿里云数据库白名单配置)

466 阅读3分钟

解决方案简介

在首次购买阿里云数据库时,用户通常需要配置访问者的IP白名单。然而,获取访问者的IP地址可能会变得复杂,特别是当存在代理或IP跳转时。为了帮助用户快速获取“最外层的IP地址”,本文提供了一个API来显示当前访问者的IP,并方便地将其添加到阿里云数据库的IP白名单中。

最终的使用方式是:页面显示的IP(如xx.xx.xx.xx)后面加上 /24 后缀,生成最终白名单IP。例如,如果显示的IP是 30.3.44.51,则需要将其改为 30.3.44.0/24

虽然这种功能应该由云厂商提供,国内部分大厂并未实现这一功能,本文将通过Rust语言的Actix框架自定义实现此功能。

环境准备

在开始之前,确保已经安装了Rust开发环境。若尚未安装,请按照官方安装指南进行安装。

创建项目

  1. 打开终端,运行以下命令创建一个新的Rust项目:

    cargo new actix_demo
    cd actix_demo
    
  2. 打开项目根目录下的 Cargo.toml 文件,并添加 Actix Web 的依赖:

    [dependencies]
    actix-web = "4"
    

编写代码

接下来,编写代码实现一个简单的Web应用,返回访问者的IP地址。

  1. 打开 src/main.rs 文件,并将其内容替换为以下代码:

    use actix_web::{get, App, HttpServer, HttpResponse, Responder};
    use actix_web::web;
    
    // 处理根路径GET请求,返回客户端的IP地址
    #[get("/")]
    async fn get_ip(req: web::HttpRequest) -> impl Responder {
        // 获取客户端的IP地址
        let ip = req.peer_addr().map(|addr| addr.ip().to_string()).unwrap_or_else(|| "未知".to_string());
        HttpResponse::Ok().body(format!("您的IP地址是: {}", ip))
    }
    
    #[actix_web::main]
    async fn main() -> std::io::Result<()> {
        HttpServer::new(|| {
            App::new().service(get_ip)
        })
        .bind("127.0.0.1:8080")? // 绑定到本地8080端口
        .run()
        .await
    }
    

    该代码的工作流程如下:

    • 使用 #[get("/")] 宏定义一个处理根路径GET请求的异步函数 get_ip
    • get_ip 函数中获取请求的客户端IP地址并返回。如果获取成功,返回 "您的IP地址是: ",否则返回 "未知"。
    • main 函数中创建一个HTTP服务器,将 get_ip 作为服务注册到服务器。
    • 服务器绑定到 127.0.0.1:8080(本地8080端口)。

运行应用

  1. 在终端中运行以下命令启动应用:

    cargo run
    

    如果看到类似 Starting 8 workers 的输出,说明服务器已经成功启动。

测试应用

  1. 打开浏览器,访问 http://localhost:8080,您应该会看到类似以下的消息:

    您的IP地址是: 127.0.0.1
    

    这个IP地址是您访问服务器时的客户端IP地址。

小结

通过这个简单的示例,您已经成功使用Rust和Actix框架创建了一个Web应用,并实现了获取并返回访问者IP地址的功能。Actix Web 因其高性能和并发处理能力,特别适合开发高效、响应迅速的Web应用。


扩展功能:获取其他信息

  1. 通过修改 get_ip 函数,您可以获取请求中的其他信息,如请求头、路径等。例如,获取用户的 User-Agent

    async fn get_user_agent(req: web::HttpRequest) -> impl Responder {
        let user_agent = req.headers().get("User-Agent")
            .and_then(|header| header.to_str().ok())
            .unwrap_or("未知");
        HttpResponse::Ok().body(format!("您的浏览器信息: {}", user_agent))
    }
    
  2. 您还可以将此功能扩展到多个路由,以便不同的请求返回不同的信息。