我正在try 使用reqwest在RUST中发出一个HTTP请求,以从网站获取数据,这与此命令的作用类似

~$ curl -X POST -H "Content-Type: application/json" -d '{"video":""}' watchparty.me/createRoom -L
{"name":"/supreme-cherries-answer"}
~$

所以这是我try 过的:

use reqwest::header;
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize, Debug)]
struct Room {
    name: String
}

async fn get_room_name() {

    //new client with cookies
    let client = reqwest::Client::builder()
        .cookie_store(true)
        .build()
        .unwrap();

    let body = r#"{
        "video": ""
    }"#;

    let res = client
        .post("https://watchparty.me/createRoom")
        .header(header::USER_AGENT, "mozilla/5.0")
        .header(header::CONTENT_TYPE, "application/json")
        .header(header::ACCEPT, "application/json")
        .body(body)
        .send()
        .await
        .unwrap();

    match res.status() {
        reqwest::StatusCode::OK => {
            //make sure response is json and not an error
            println!("Room name: {:?}", &res.text().await.unwrap());
        },
        _ => println!("Error: {}", res.status())
    }
}

#[tokio::main]
async fn main() {
    get_room_name().await;
}

问题是,在此代码中,我得到的响应是

Room name: "<!doctype html>
<html lang=\"en\">
   <head>
      <meta charset=\"utf-8\"/>
      <link rel=\"icon\" href=\"/favicon.ico\"/>
      <meta name=\"viewport\" content=\"width=device-width,initial-scale=1\"/>
      <meta name=\"theme-color\" content=\"#000000\"/>
      <meta name=\"description\" content=\"Watch together with friends. Chat and react in real time to the same stream, whether it's YouTube, your own video, or a virtual browser.\"/>
      <meta property=\"og:image\" content=\"/screenshot4.png\"/>
      <link rel=\"apple-touch-icon\" href=\"/favicon.png\"/>
      <link rel=\"manifest\" href=\"/manifest.json\"/>
      <title>WatchParty</title>
      <script defer=\"defer\" src=\"/static/js/main.437dd445.js\"></script>
      <link href=\"/static/css/main.9154545e.css\" rel=\"stylesheet\">
   </head>
   <body>
      <script>!function(){var a=\"fbclid\";if(-1!==location.search.indexOf(\"fbclid=\")){var e=\"\";try{var c=new URL(location);c.searchParams.delete(a),e=c.href}catch(a){var l=new RegExp(\"[?&]fbclid=.*$\");e=location.search.replace(l,\"\"),e=location.pathname+e+location.hash}history.replaceState(null,\"\",e)}}()</script>
      <noscript>You need to enable JavaScript to run this app.</noscript>   <----- this is the part that annoys me
      <div id=\"root\"></div>
   </body>
   <script async src=\"https://www.googletagmanager.com/gtag/js?id=UA-45337794-6\"></script><script>function gtag(){dataLayer.push(arguments)}window.dataLayer=window.dataLayer||[],gtag(\"js\",new Date),gtag(\"config\",\"UA-45337794-6\")</script>
</html>
"

我不知道如何才能使我的代码获得与我的cURL查询相同的结果(当然不使用cURL crate ),有谁有主意吗?

100我对我的代码做了一些修改,修改了一些注释,但结果是相同的

推荐答案

这是因为https://watchparty.me/createRoom只重定向了一次.从curl 的-i标志中判断:

$ curl -X POST -H "Content-Type: application/json" -d '{"video":""}' watchparty.me/createRoom -Li

HTTP/1.1 301 Moved Permanently
Date: Thu, 04 May 2023 15:24:47 GMT
Transfer-Encoding: chunked
Connection: keep-alive
Cache-Control: max-age=3600
Expires: Thu, 04 May 2023 16:24:47 GMT
Location: https://www.watchparty.me/createRoom
Report-To: {"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v3?s=MuWcCoj86EW9kl2orX6SpVlY%2B%2Fgwb6DR5637tSa6IFfs16RUyAYQXnGVZ9mrJHjkebAQTf789SlAboTzu03kmtO0v22WCJryTv3iKhI92WUyLEuYWyHOX4qp5S8Y8kjl"}],"group":"cf-nel","max_age":604800}
NEL: {"success_fraction":0,"report_to":"cf-nel","max_age":604800}
Server: cloudflare
CF-RAY: 7c21c0aec93585d6-BOM
alt-svc: h3=":443"; ma=86400, h3-29=":443"; ma=86400

HTTP/2 200 
date: Thu, 04 May 2023 15:24:49 GMT
content-type: application/json; charset=utf-8
content-length: 38
x-powered-by: Express
access-control-allow-origin: *
etag: W/"26-umy5SJpIYT3XtIZYL82SfSgo4zs"
vary: Accept-Encoding
cf-cache-status: DYNAMIC
report-to: {"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v3?s=MNv3ogdbLprH82OGlphP%2Bdau%2BFbB%2By2gjhsYwi16qQEEtaTVYvPrupsx5YGRUHKENqFVv%2BQ3GWn5bxRS3lb40jEABv8IiQeWsfzYvS%2F3r5eaGhjE3f5v6PPLUDU0S%2Fj3Hue4uA%3D%3D"}],"group":"cf-nel","max_age":604800}
nel: {"success_fraction":0,"report_to":"cf-nel","max_age":604800}
server: cloudflare
cf-ray: 7c21c0b8cbaad393-CDG
alt-svc: h3=":443"; ma=86400, h3-29=":443"; ma=86400

{"name":"/unbecoming-pizzas-preserve"}

要更新代码:将您的URL:https://watchparty...替换为https://www.watchparty....以下是经过测试的代码:

use reqwest::header;
// use serde::{Deserialize, Serialize};
// We don't need Room struct and serde actually
// struct Room {
//     name: String
// }

async fn get_room_name() {
    let client = reqwest::Client::builder()
        .build()
        .unwrap();

    let body = r#"{
        "video": ""
    }"#;

    let res = client
        .post("https://www.watchparty.me/createRoom")
        .header(header::USER_AGENT, "mozilla/5.0")
        .header(header::CONTENT_TYPE, "application/json")
        .header(header::ACCEPT, "application/json")
        .body(body)
        .send()
        .await
        .unwrap();

    match res.status() {
        reqwest::StatusCode::OK => {
            println!("Room name: {:?}", &res.text().await.unwrap());
        },
        _ => println!("Error: {}", res.status())
    }
}

#[tokio::main]
async fn main() {
    get_room_name().await;
}

其输出:

$ cargo run
   Compiling soTesting v0.1.0 (/home/cpp23g/rustProjects/soTesting)
    Finished dev [unoptimized + debuginfo] target(s) in 3.41s
     Running `target/debug/soTesting`
Room name: "{\"name\":\"/tasty-animal-heap\"}"

事实上,我们可以干净利落地将其重写为(当然是经过测试的):

use reqwest;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = reqwest::Client::new();
    let res = client.post("https://www.watchparty.me/createRoom")
        .header("Content-Type", "application/json")
        .body(r#"{"video":""}"#)
        .send()
        .await?;
    println!("{}", res.text().await?);
    Ok(())
}

Rust相关问答推荐

如何在 struct 中填充缓冲区并同时显示它?

如何从Rust记录WASM堆内存使用情况?

如何从接收&;self的方法克隆RC

两个相关特征的冲突实现错误

当两者都有效时,为什么Rust编译器建议添加';&;而不是';*';?

取得本地对象字段的所有权

什么时候和为什么S最好是按值或引用传递简单类型

是否提供Bundle 在可执行文件中的warp中的静态文件?

如何轮询 Pin>?

为什么 `Deref` 没有在 `Cell` 上实现?

在 Rust 中,是否可以定义一个需要实现类型的构造函数的对象安全特征?

仅发布工作区的二进制 crate

通过写入 std::io::stdout() 输出不可见

返回优化后的标题:返回异步块的闭包的类型擦除

为什么数组不像向量那样在 for 块之后移动?

&str 的编译时拆分是否可能?

第 7.4 章片段中如何定义 `thread_rng`

实现不消费的迭代器

如何在 Rust 的内置函数上实现特征?

类型参数不受 impl 特征、自身类型或谓词的约束