代码之家  ›  专栏  ›  技术社区  ›  sudoExclamationExclamation

如何在Rust-Axum的ConnectInfo自定义插件中访问用户代理?

  •  0
  • sudoExclamationExclamation  · 技术社区  · 11 月前

    阿克苏姆 into_make_service_with_connect_info 如果是远程地址,则提供以下访问IP地址的方式:

    https://docs.rs/axum/latest/axum/struct.Router.html#method.into_make_service_with_connect_info

    注意它是怎么说的:

    您可以按如下方式实现自定义Connected:

    async fn handler(
        ConnectInfo(my_connect_info): ConnectInfo<MyConnectInfo>,
    ) -> String {
        format!("Hello {my_connect_info:?}")
    }
    
    #[derive(Clone, Debug)]
    struct MyConnectInfo {
        // ...
    }
    
    impl Connected<IncomingStream<'_, TcpListener>> for MyConnectInfo {
        fn connect_info(target: IncomingStream<'_, TcpListener>) -> Self {
            MyConnectInfo {
                // ...
            }
        }
    }
    

    我可以用这个来定制 MyConnectionInfo 它可以通过我的所有路线访问:

    #[derive(Clone, Debug)]
    struct MyConnectionInfo {
        ip: String,
        user_agent: String,
    }
    
    impl Connected<IncomingStream<'_, TcpListener>> for MyConnectionInfo {
        fn connect_info(target: IncomingStream<'_, TcpListener>) -> Self {
            MyConnectionInfo {
                ip: target.remote_addr().to_string(), user_agent: "Firefox".to_string()
            }
        }
    }
    

    我能够成功获得 target.remote_addr() 。但是,对于用户代理,我不确定如何在此自定义中访问它 impl (注意当前硬编码的“Firefox”字符串)。

    Axum提供了一种从以下位置获取用户代理的方法 TypedHeader 如下所示:

    https://docs.rs/axum/latest/axum/extract/index.html

    是否可以在我的自定义中访问此用户代理和其他标头 impl ?

    还是我的方法错了?

    2 回复  |  直到 11 月前
        1
  •  1
  •   kmdreko    11 月前

    您无法从访问用户代理 Connected 实施。

    它用于从底层检索元数据 连接 TcpStream 在典型条件下。另一方面,用户代理只能从尚未解析的HTTP标头访问。

    如果你不需要TCP层的任何东西,除了什么 ConnectInfo 已经可以得到,你可能只是想要一个自定义提取器(通过 FromRequestParts 实现),您可以从中获得现有的 连接信息 以及任何 TypedHeader 这是您对处理程序或中间件的要求。

        2
  •  0
  •   sudoExclamationExclamation    11 月前

    在@kmdreko的建议下,我能够解决这个问题:

    首先添加 connection_info_middleware 作为一个 middleware route_layer 并添加 app.into_make_service_with_connect_info::<SocketAddr>() 轻松获取IP地址:

    let app = axum::Router::new()
        .route("/signin", get(auth_get).post(auth_post))
        .route("/register", get(auth_get).post(auth_post))
        .route("/", get(page))
        .route_layer(axum::middleware::from_fn(connection_info_middleware));
    
    let listener = tokio::net::TcpListener::bind(":::8080").await.unwrap();
    axum::serve(listener, app.into_make_service_with_connect_info::<SocketAddr>()).await.unwrap();
    

    创建此 struct :

    #[derive(Clone, Debug)]
    struct ConnectionInfo {
        ip: String,
        user_agent: String,
    }
    

    然后在中间件函数中:

    async fn connection_info_middleware(user_agent: Option<TypedHeader<UserAgent>>, addr: ConnectInfo<SocketAddr>, mut request: Request, next: Next) -> Response {
    
        let user_agent = match user_agent {
            Some(u) => u,
            None => {
                return Html("UserAgent is missing.").into_response()
            },
        };
    
        request.extensions_mut().insert(ConnectionInfo {ip: addr.to_string(), user_agent: user_agent.to_string()});
        next.run(request).await
    
    }
    

    现在,您将可以访问您的 connection_info 所有路由处理程序中的struct:

    pub async fn page(state: State<AppState>, matched_path: MatchedPath, cookies: CookieJar, params : Query<QueryParams>, connection_info: Extension<ConnectionInfo>) -> Response {
    
        println!("connection_info: {:?}",connection_info);
    
    ....
    
    }
    
    推荐文章