【问题标题】:Is there simpler method to get the string value of an Actix-Web HTTP header?是否有更简单的方法来获取 Actix-Web HTTP 标头的字符串值?
【发布时间】:2021-02-13 04:17:14
【问题描述】:

这是从 Actix-Web 请求中获取内容类型标头的唯一可能性吗?这必须检查标头是否可用或to_str 是否失败...

let req: actix_web::HttpRequest;

let content_type: &str = req
    .request()
    .headers()
    .get(actix_web::http::header::CONTENT_TYPE)
    .unwrap()
    .to_str()
    .unwrap();

【问题讨论】:

  • str != String !
  • 这应该告诉我什么?我知道 str 与 String 不同...第一个展开不返回 String,这是一个 HeaderValue,如果这是这个想法...还是因为标题?我已经输入了一个“字符串值”。 ;-)
  • 我想你可以用.and_then(HeaderValue::to_str) 替换.unwrap().to_str() 以减少恐慌风险。

标签: rust rust-actix


【解决方案1】:

是的,这是“唯一”的可能性,但就是这样,因为:

  1. 标头可能不存在,headers().get(key) 返回Option
  2. 标头可能包含非 ASCII 字符,HeaderValue::to_str 可能会失败。

actix-web 允许您单独处理这些错误。

为简化起见,您可以创建一个不区分这两个错误的辅助函数:

fn get_content_type<'a>(req: &'a HttpRequest) -> Option<&'a str> {
    req.headers().get("content-type")?.to_str().ok()
}

完整示例:

use actix_web::{web, App, HttpRequest, HttpServer, Responder};

fn main() {
    HttpServer::new(|| App::new().route("/", web::to(handler)))
        .bind("127.0.0.1:8000")
        .expect("Cannot bind to port 8000")
        .run()
        .expect("Unable to run server");
}

fn handler(req: HttpRequest) -> impl Responder {
    if let Some(content_type) = get_content_type(&req) {
        format!("Got content-type = '{}'", content_type)
    } else {
        "No content-type header.".to_owned()
    }
}

fn get_content_type<'a>(req: &'a HttpRequest) -> Option<&'a str> {
    req.headers().get("content-type")?.to_str().ok()
}

这会给你结果:

$ curl localhost:8000
No content-type header.⏎
$ curl localhost:8000 -H 'content-type: application/json'
Got content-type = 'application/json'⏎
$ curl localhost:8000 -H 'content-type: ?'
No content-type header.⏎

对了,你可能对guards感兴趣:

web::route()
    .guard(guard::Get())
    .guard(guard::Header("content-type", "text/plain"))
    .to(handler)

【讨论】:

  • 好的。我预计 web 框架会提供类似于您的 fn get_content_type 的东西,并不是每个人都需要重新发明它。不过谢谢。
  • @Markus 取决于您的观点。 actix-web 为您提供了 HTTP 协议的 API,其中包含所有可能失败的内容。在这个较低级别的上下文中,获取内容类型是直截了当的。如果你只想在更高的层次上工作,你可以复制这段代码并发布到 crates.io ?
【解决方案2】:

我从路线中使用以下内容:

#[get("/auth/login")]
async fn login(request: HttpRequest, session: Session) -> Result<HttpResponse, ApiError> {
    let req_headers = request.headers();

    let basic_auth_header = req_headers.get("Authorization");
    let basic_auth: &str = basic_auth_header.unwrap().to_str().unwrap();
    // Keep in mind that calling "unwrap" here could make your application
    // panic. The right approach at this point is to evaluate the resulting
    // enum variant from `get`'s call

    println!("{}", basic_auth); // At this point I have the value of the header as a string

    // ...
}

【讨论】:

  • 请原谅我的新手问题,但是当您的解包失败时,Actix 会做什么/返回,例如,如果您在标题值中有一个表情符号?
  • 没问题,所有问题都是有效问题!当您在任何值上调用 unwrap 时,如果生成的变体是 ErrNone(基于返回的类型)并且应用程序退出,Rust 您的线程将恐慌。不建议大部分时间使用unwrap,正确的做法是处理get调用产生的变体。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多