rust 如何为www.example.com设置CORS或OPTIONSRocket.rs

csbfibhn  于 2023-02-23  发布在  其他
关注(0)|答案(8)|浏览(143)

我有一个运行www.example.com的后端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

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

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请求的正确方法吗?如果不是,我如何在www.example.com中实现它rocket.rs?

wko9yo5t

wko9yo5t1#

为了使服务器提供外部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<'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"));
    }
}

你只需要像这样安装整流罩:

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和访问控制标头的详细信息 *
pbwdgjma

pbwdgjma2#

我在使用火箭0.5.0-rc.2的时候也是这样,没有其他依赖项。这是基于上面的答案和一些互联网搜索。

use rocket::fairing::{Fairing, Info, Kind};
use rocket::http::Header;
use rocket::log::private::debug;
use rocket::serde::json::Json;
use rocket::{Request, Response};

#[macro_use]
extern crate rocket;

#[launch]
fn rocket() -> _ {
    rocket::build()
        .attach(Cors)
        .mount("/", routes![index, all_options, insert])
}

/// Some getter
#[get("/")]
fn index() -> &'static str {
    "Hello CORS"
}

/// Some setter
#[post("/", data = "<data>")]
async fn insert(data: Json<Vec<String>>) {
    debug!("Received data");
}

/// Catches all OPTION requests in order to get the CORS related Fairing triggered.
#[options("/<_..>")]
fn all_options() {
    /* Intentionally left empty */
}

pub struct Cors;

#[rocket::async_trait]
impl Fairing for Cors {
    fn info(&self) -> Info {
        Info {
            name: "Cross-Origin-Resource-Sharing Fairing",
            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, PATCH, PUT, DELETE, HEAD, OPTIONS, GET",
        ));
        response.set_header(Header::new("Access-Control-Allow-Headers", "*"));
        response.set_header(Header::new("Access-Control-Allow-Credentials", "true"));
    }
}
toiithl6

toiithl63#

这对我很有效:

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])
}
pjngdqdw

pjngdqdw4#

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
r6vfmomb

r6vfmomb5#

如果有人正在寻找火箭〉= 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"));
    }
}
cnjp1d6j

cnjp1d6j6#

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

Rocket版本0.5.x(不稳定)

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

Trait implemented by fairings: Rocket’s structured middleware.

来源
您必须使用rocket::async-trait属性来修饰Fairingtrait实现。

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(稳定)

参见Ibraheem Ahmed answer

tjvv9vkg

tjvv9vkg7#

天啊。几个小时后我终于让它工作了。首先也是最重要的,一个小警告:我们使用的是高度不稳定的代码,这个答案可能在你阅读的时候已经过时了,但在Ibraheem Ahmeed的答案中,matthewscottgordon的编辑为我指出了正确的方向。
我们将使用rocket_cors板条箱。

1.安装一个旧版本的Rust Nightly。从1月22日起,Rust Nightly V1.6.0将突破mongodb 2.1.0。

这样做只是为了防止最新的夜间没有编译。
您可以通过以下方式执行此操作:
rustup覆盖设置每晚-2021-11-10这将下载1.58每晚。

2.添加rocket_cors依赖项。到目前为止,主版本有一个1.6.0发行版,目标是rocket的0.5.0-rc.1发行版

搜索结果= { git =“https://github.com/lawliet89/rocket_cors“,分支=“master”}
这是我的货

[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 repository以获取最新示例。上面的示例与fairing.rs文件一起使用
查看repo的Cargo.toml文件。
要检查let cors中的默认值,(如果使用VS代码和Rust扩展)将鼠标悬停在CorsOptions上。

30byixjq

30byixjq8#

感谢这里的答案和这个GitHub评论,我在Rocket v0.5-rc的服务中得到了这个。
对于我的用例,我不需要为特定的请求定制CORS头,如果您有更详细的需求,请使用rocket_cors
创建CORS Fairing以设置每个响应的CORS标头。

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

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, request: &'r Request<'_>, response: &mut Response<'r>) {
        if request.method() == Method::Options {
            response.set_status(Status::NoContent);
            response.set_header(Header::new(
                "Access-Control-Allow-Methods",
                "POST, PATCH, GET, DELETE",
            ));
            response.set_header(Header::new("Access-Control-Allow-Headers", "*"));
        }

        response.set_header(Header::new(
            "Access-Control-Allow-Origin",
            "http://localhost:3000",
        ));
        response.set_header(Header::new("Access-Control-Allow-Credentials", "true"));
    }
}

然后用rocket::build().attach(cors::CORS)把这个整流罩固定在火箭上,就万事俱备了。
以上的回答完全归功于他们,因为这在很大程度上受到了他们的启发。遗漏的重要部分是为所有选项请求设置NoContent状态。谢天谢地,Domenico Gaeni的示例包括以下内容:

response.set_status(Status::NoContent)

没有这个火箭将404对每一个选项请求。通过设置在整流罩这里的状态,没有必要定义任何特殊的路线,以服务选项请求。
如果你使用这篇笔记,Access-Control-Allow-Origin的头文件需要根据你的用例定制,我把它硬编码为http://localhost:3000,因为我不能让自己使用*,以防有人完整地复制粘贴它。
在真实的生活中,您可能希望根据请求源头或Rocket.toml配置或两者来设置Access-Control-Allow-Origin,以便支持本地开发和测试/登台/生产服务器。

相关问题