如何从GET响应中获取Cookie?

时间:2017-12-17 09:27:26

标签: http cookies rust hyper

我正在编写一个向网站发出GET请求并返回响应cookie的函数:

extern crate futures;
extern crate hyper;
extern crate tokio_core;

use tokio_core::reactor::Core;
use hyper::Client;
use std::error::Error;
use hyper::header::Cookie;
use futures::future::Future;

fn get_new_cookie() -> Result<String, Box<Error>> {
    println!("Getting cookie...");
    let core = Core::new()?;
    let client = Client::new(&core.handle());
    println!("Created client");

    let uri = "http://www.cnn.com".parse().expect("Cannot parse url");
    println!("Parsed url");
    let response = client.get(uri).wait().expect("Cannot get url.");
    println!("Got response");
    let cookie = response
        .headers()
        .get::<Cookie>()
        .expect("Cannot get cookie");
    println!("Cookie: {}", cookie);

    Ok(cookie)
}

fn main() {
    println!("{:?}", get_new_cookie());
}

这不起作用;它卡在client.get(...)字符串上。我得到的输出是:

Getting cookie...
Created client
Parsed url

之后没有任何事情发生。

我做错了什么以及如何改变它以便它起作用?

2 个答案:

答案 0 :(得分:2)

请参阅documentation for the wait method

  

注意:此方法不适合调用事件循环或类似方法   I / O情况因为它会阻止事件循环的产生   进度(阻止线程)。只应调用此方法   当它保证阻止工作与此相关时   未来将由另一个线程完成。

Future::wait已经是deprecated in the tokio-reform分支。

我建议设计完整的应用程序来处理异步概念(即get_new_cookie应该采用Handle并返回Future,而不是分配自己的事件循环)

您可以使用Core::run运行请求,如下所示:

let response = core.run(client.get(uri)).expect("Cannot get url.");

答案 1 :(得分:2)

作为Stefan points out,通过调用wait,您将使线程处于睡眠状态,直到将来完成为止。但是,该线程需要运行事件循环,因此您只是导致死锁。使用Core::run更为正确。

作为Francis Gagné points out,“Cookie”标头用于将Cookie 发送到服务器SetCookie用于将Cookie 发送到客户端。它还会返回所有cookie的向量:

fn get_new_cookie() -> Result<String, Box<Error>> {
    println!("Getting cookie...");
    let mut core = Core::new()?;

    let client = Client::new(&core.handle());
    println!("Created client");

    let uri = "http://www.cnn.com".parse().expect("Cannot parse url");
    println!("Parsed url");

    let response = core.run(client.get(uri)).expect("Cannot get url.");
    println!("Got response");

    let cookie = response
        .headers()
        .get::<SetCookie>()
        .expect("Cannot get cookie");
    println!("Cookie: {:?}", cookie);

    Ok(cookie.join(","))
}

但是,如果您只想要同步API,请改用Reqwest。它建立在Hyper之上:

extern crate reqwest;

use std::error::Error;
use reqwest::header::SetCookie;

fn get_new_cookie() -> Result<String, Box<Error>> {
    let response = reqwest::get("http://www.cnn.com")?;

    let cookies = match response.headers().get::<SetCookie>() {
        Some(cookies) => cookies.join(","),
        None => String::new(),
    };

    Ok(cookies)
}

fn main() {
    println!("{:?}", get_new_cookie());
}
相关问题