7

我有一个运行 Rocket.rs 的后端,我的 Flutter Web 应用程序向它发送请求,但它无法通过 OPTIONS 响应。

我尝试将 CORS (rocket_cors) 添加到后端并获得选项响应,但它仍然发回:

Error: XMLHttpRequest error.
    dart:sdk_internal 124039:30                           get current
packages/http/src/browser_client.dart.lib.js 214:124  <fn>

我在我的火箭项目中添加了以下内容:

#[options("/")]
fn send_options<'a>(path: PathBuf) -> Response<'a> {
    let mut res = Response::new();
    res.set_status(Status::new(200, "No Content"));
    res.adjoin_header(ContentType::Plain);
    res.adjoin_raw_header("Access-Control-Allow-Methods", "POST, GET, OPTIONS");
    res.adjoin_raw_header("Access-Control-Allow-Origin", "*");
    res.adjoin_raw_header("Access-Control-Allow-Credentials", "true");
    res.adjoin_raw_header("Access-Control-Allow-Headers", "Content-Type");
    res

我的颤振应用程序正在运行这个请求:

Future<String> fetchData() async {
  final data2 = await http.get("http://my-web-site.com").then((response) { // doesn't get past here
    return response.body; 
  });
  return data2;
}

问题:这是响应 OPTION 请求的正确方法吗?如果不是,我如何在 Rocket.rs 中实现它?

4

6 回答 6

13

为了让服务器提供外部 API,它需要能够处理跨域资源共享 (CORS)。CORS 是一种基于 HTTP 标头的机制,它允许服务器指示浏览器应允许加载资源的来源(域、协议或端口)。

您可以创建一个整流罩来为您的应用程序全局处理 CORS。一个非常宽松的版本如下,但当然,您必须根据您的特定应用程序进行定制。

火箭0.4

use rocket::http::Header;
use rocket::{Request, Response};
use rocket::fairing::{Fairing, Info, Kind};

pub struct CORS;

impl Fairing for CORS {
    fn info(&self) -> Info {
        Info {
            name: "Add CORS headers to responses",
            kind: Kind::Response
        }
    }

    fn on_response(&self, request: &Request, response: &mut Response) {
        response.set_header(Header::new("Access-Control-Allow-Origin", "*"));
        response.set_header(Header::new("Access-Control-Allow-Methods", "POST, GET, PATCH, OPTIONS"));
        response.set_header(Header::new("Access-Control-Allow-Headers", "*"));
        response.set_header(Header::new("Access-Control-Allow-Credentials", "true"));
    }
}

火箭0.5

use rocket::http::Header;
use rocket::{Request, Response};
use rocket::fairing::{Fairing, Info, Kind};

pub struct CORS;

#[rocket::async_trait]
impl Fairing for CORS {
    fn info(&self) -> Info {
        Info {
            name: "Add CORS headers to responses",
            kind: Kind::Response
        }
    }

    async fn on_response(&self, _request: &'r Request<'_>, response: &mut Response<'r>) {
        response.set_header(Header::new("Access-Control-Allow-Origin", "*"));
        response.set_header(Header::new("Access-Control-Allow-Methods", "POST, GET, PATCH, OPTIONS"));
        response.set_header(Header::new("Access-Control-Allow-Headers", "*"));
        response.set_header(Header::new("Access-Control-Allow-Credentials", "true"));
    }
}

你只需要像这样连接整流罩:

rocket::ignite().attach(CORS)

或者,您可以使用rocket_cors板条箱。

use rocket::http::Method;
use rocket_cors::{AllowedOrigins, CorsOptions};

let cors = CorsOptions::default()
    .allowed_origins(AllowedOrigins::all())
    .allowed_methods(
        vec![Method::Get, Method::Post, Method::Patch]
            .into_iter()
            .map(From::from)
            .collect(),
    )
    .allow_credentials(true);

rocket::ignite().attach(cors.to_cors().unwrap())

您可以在此处了解有关 CORS 和访问控制标头的更多信息

于 2020-11-19T03:22:01.377 回答
4

这对我有用:

use rocket::http::Header;
use rocket::{Request, Response};
use rocket::fairing::{Fairing, Info, Kind};

pub struct CORS;

#[rocket::async_trait]
impl Fairing for CORS {
    fn info(&self) -> Info {
        Info {
            name: "Attaching CORS headers to responses",
            kind: Kind::Response
        }
    }

    async fn on_response<'r>(&self, _request: &'r Request<'_>, response: &mut Response<'r>) {
        response.set_header(Header::new("Access-Control-Allow-Origin", "*"));
        response.set_header(Header::new("Access-Control-Allow-Methods", "POST, GET, PATCH, OPTIONS"));
        response.set_header(Header::new("Access-Control-Allow-Headers", "*"));
        response.set_header(Header::new("Access-Control-Allow-Credentials", "true"));
    }
}

您必须使用启动宏将其附加到函数中:

#[launch]
fn rocket() -> _ {
    rocket::build()
        .attach(CORS)
        .mount("/index", routes![index])
}
于 2021-09-27T06:41:05.687 回答
2

Lambda Fairy 的评论为我回答了这个问题。
我把它全部放在GET处理程序中:

#[get("/")]
fn get_handler<'a>() -> Response<'a> {
    let mut res = Response::new();
    res.set_status(Status::new(200, "No Content"));
    res.adjoin_header(ContentType::Plain);
    res.adjoin_raw_header("Access-Control-Allow-Methods", "POST, GET, OPTIONS");
    res.adjoin_raw_header("Access-Control-Allow-Origin", "*");
    res.adjoin_raw_header("Access-Control-Allow-Credentials", "true");
    res.adjoin_raw_header("Access-Control-Allow-Headers", "Content-Type");
    res.set_sized_body(Cursor::new("Response")); 
    res
于 2020-06-17T13:07:02.383 回答
1

要获得跨域资源共享支持,您必须拦截 Rocket 服务器发送的响应。你想实现一个中间件来实现这一点,在 Rocket 上你必须Fairing在 a 上实现特征struct才能实现这一点。

Rocket v0.5.x(不稳定)

如果您在 Rocket 的文档中搜索 0.5.x 版本。

Trait implemented by fairings: Rocket’s structured middleware.

资源

您必须使用Rocket::async-trait 属性来装饰 Fairing trait实现。

use rocket::fairing::{Fairing, Info, Kind};
use rocket::http::Header;
use rocket::{Request, Response};

pub struct Cors;

#[rocket::async_trait]
impl Fairing for Cors {
    fn info(&self) -> Info {
        Info {
            name: "Cross-Origin-Resource-Sharing Middleware",
            kind: Kind::Response,
        }
    }

    async fn on_response<'r>(&self,
        request: &'r Request<'_>,
        response: &mut Response<'r>) {
        response.set_header(Header::new(
            "access-control-allow-origin",
            "https://example.com",
        ));
        response.set_header(Header::new(
            "access-control-allow-methods",
            "GET, PATCH, OPTIONS",
        ));
    }
}

在您的main.rs文件中,您必须附加中间件:

mod config;
mod middleware;
mod routes;

use self::config::Config;

#[macro_use]
extern crate rocket;

#[launch]
async fn rocket() -> _ {
    let config = Config::new();

    rocket::custom(&config.server_config)
        .attach(middleware::cors::Cors)
        .mount(
            "/api/v1",
            routes![routes::index],
        )
}

火箭 0.4.x(稳定)

参考易卜拉欣·艾哈迈德的回答

于 2021-10-18T02:41:35.707 回答
1

如果有人正在寻找火箭> = rc5.0

use rocket::http::Header;
use rocket::{Request, Response};
use rocket::fairing::{Fairing, Info, Kind};

pub struct CORS;

#[rocket::async_trait]
impl Fairing for CORS {
    fn info(&self) -> Info {
        Info {
            name: "Add CORS headers to responses",
            kind: Kind::Response
       }
    }


    async fn on_response<'r>(&self, req: &'r Request<'_>, response: &mut Response<'r>) {
        response.set_header(Header::new("Access-Control-Allow-Origin", "*"));
        response.set_header(Header::new("Access-Control-Allow-Methods", "POST, GET, PATCH, OPTIONS"));
        response.set_header(Header::new("Access-Control-Allow-Headers", "*"));
        response.set_header(Header::new("Access-Control-Allow-Credentials", "true"));
    }
}
于 2021-11-25T01:35:07.813 回答
1

耶稣。几个小时后,我终于让它工作了。首先,一个小警告:我们正在处理高度不稳定的代码,当您阅读时,这个答案可能已经过时了。易卜拉欣·艾哈迈德(Ibraheem Ahmeed)的回答中来自 matthewscottgordon 的编辑为我指明了正确的方向。

我们将使用rocket_cors箱子。

1. 安装旧版本的 Rust Nightly。截至 1 月 22 日,Rust Nightly V 1.6.0 打破了 mongodb 2.1.0。

这样做以防万一最新的每晚没有编译。

您可以通过以下方式执行此操作:

rustup override set nightly-2021-11-10 这将每晚下载 1.58。

2. 添加rocket_cors 依赖。截至目前,master 版本有 1.6.0 版本,目标是 Rocket 的 0.5.0-rc.1 版本

Rocket_cors = { git = "https://github.com/lawliet89/rocket_cors", 分支 = "master" }

这是我的 cargo.toml:


[dependencies]
rocket = {version ="0.5.0-rc.1", features=["json"]}
rocket_cors = { git = "https://github.com/lawliet89/rocket_cors", branch = "master" }
reqwest = {version = "0.11.6", features = ["json"] }
serde= {version = "1.0.117", features= ["derive"]}
mongodb = "2.1.0"
rand = "0.8.4"

3. 将以下内容添加到您的主要 Rocket 函数中:

extern crate rocket;

use std::error::Error;
use rocket_cors::{AllowedOrigins, CorsOptions};

#[rocket::main]
async fn main() -> Result<(), Box<dyn Error>> {
    let cors = CorsOptions::default()
        .allowed_origins(AllowedOrigins::all())
        .allowed_methods(
            vec![Method::Get, Method::Post, Method::Patch]
                .into_iter()
                .map(From::from)
                .collect(),
        )
        .allow_credentials(true)
        .to_cors()?;

    // let path = concat!(env!("CARGO_MANIFEST_DIR"), "/public");
    rocket::build()
        .mount("/", routes![index, upload::upload, post_favorites])
        .attach(cors)
        .launch()
        .await?;


    Ok(())
}

如果这个答案对您不起作用,请务必查看Rocket_cors 存储库以获取最新示例。上面的示例与fairing.rs文件一起使用

查看 repo 的Cargo.toml文件。

要检查 中的默认值let cors,(如果使用 VS Code 和 Rust 扩展)将鼠标悬停在CorsOptions上面。

于 2022-01-23T04:17:41.227 回答