Rust开发问题记录

cannot find derive macro Deserializ in this scope

error: cannot find derive macro `Serialize` in this scope
 --> common/src/result.rs:2:10
  |
2 | #[derive(Serialize,Deserializ)]
  |          ^^^^^^^^^

error: cannot find derive macro `Deserializ` in this scope
 --> common/src/result.rs:2:20
  |
2 | #[derive(Serialize,Deserializ)] 

在新版本的serde中使用derive需要开启对应的features

serde = { version = "1.0", features = ["derive"] }

参考serde官网文档


cannot infer type for Conn

error[E0282]: type annotations needed
  --> user/src/lib.rs:29:31
   |
29 |         let count:  usize  =  repos::add_login_info( conn,   &new_login_info).expect("add login info error");
   |                               ^^^^^^^^^^^^^^^^^^^^^ cannot infer type for `Conn`

刚开始以为是推导不出参数conn的类型,甚是奇怪,仔细看发现是Conn一个全小写一个首字母大写,代码里也没用到Conn啊,是不是调diesel API里的,在翻看diesel文档时确实见过Conn

fn execute(self, conn: &Conn) -> QueryResult<usize>
where
    **Conn**: Connection,
    Self: ExecuteDsl<Conn>

查API也没发现泛型参数,最终发现是自己的代码里声明了个泛型Conn,没有用到忘记删掉了。

pub fn add_login_info<Conn>(conn:  &MysqlConnection, new_login_info: &NewLoginInfo) -> Result<usize,  Error>

在网上看到这个问题

What is the best approach to implement http authentication
(validation) using actix web?

Using the provided examples for a simple-auth-server I can
authenticate a request and create a cookie accordingly.

Now I want to validate the cookie/identity in order to prevent access
from certain routes. A Guard 3 doesn’t cut it because I can only
retrieve the stored identity using Identity::from_request(HttpRequest,
Payload) and in RequestHead (guard implementation), there is neither
the full request nor its payload.

I can not use Middleware 3 either because I will only get access to
ServiceRequest but not HttpRequest.

看样子是想基于Session做登录验证,但官方的Demo只有使用Cookie Identity的,那我们就实现个吧
一个基于Session验证用户是否登录的中间件:

use std::cell::RefCell;
use std::ops::{Deref, DerefMut};
use std::pin::Pin;
use std::rc::Rc;
use std::sync::Arc;
use std::task::{Context, Poll};

use futures::future::{ok, Ready};
use futures::Future;

use actix_service::{Service, Transform};
use actix_web::{dev::ServiceRequest, dev::ServiceResponse, Error, HttpMessage, HttpResponse};
use actix_session::{UserSession};

use log::{info};

use super::userctrl;

#[derive(Clone)]
pub struct AuthService {
}

impl<S, B> Transform<S> for AuthService
where
    S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = Error> + 'static,
    S::Future: 'static,
    B: 'static,
{
    type Request = ServiceRequest;
    type Response = ServiceResponse<B>;
    type Error = Error;
    type InitError = ();
    type Transform = AuthMiddleware<S>;
    type Future = Ready<Result<Self::Transform, Self::InitError>>;

    fn new_transform(&self, service: S) -> Self::Future {
        ok(AuthMiddleware {
            service: Rc::new(RefCell::new(service)),
        })
    }
}



pub struct AuthMiddleware<S> {
    service: Rc<RefCell<S>>,
}

impl<S, B> Service for AuthMiddleware<S>
where
    S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = Error> + 'static,
    S::Future: 'static,
    B: 'static,
{
    type Request = ServiceRequest;
    type Response = ServiceResponse<B>;
    type Error = Error;
    type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>>>>;

    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        self.service.poll_ready(cx)
    }

    fn call(&mut self, req: ServiceRequest) -> Self::Future {
        let mut srv = self.service.clone();
        Box::pin(async move {
            let path = req.path().to_string();
            info!("path:{}", path);
            if path.find("/admin") .is_some() &&  userctrl::get_username_from_session(req.get_session()).is_none() {
                Ok(req.into_response(HttpResponse::Unauthorized().finish().into_body()))
            } else {
                 let res_fut = srv.call(req);
                 res_fut.await
            }
        })
    }
}

完整代码已提交github rust_cms

部署的Rust应用启动时报:

/lib64/libc.so.6: version `GLIBC_2.18’ not found (required by ./web)

可以通过在生成发布包时指定不依赖glibc的发布包解决也可以在安装机器上安装对应版本的glibc解决(网上有安装glibc的教程),但是升级glibc有风险,因为很多程序都依赖这个库,最后我选择了使用docker部署rust应用。 也可以使用跟部署操作系统一样的docker环境编译生成安装包也可以使用比较低版本的glibc环境比如centos5 。解决问题的方法不只一种,找到最适合最易实现的就好。由于Rust程序中使用diesel访问mysql所以需要 libmysqlclient.so.20

libmysqlclient.so.20 not found   
参考博客执行:  
apt-get install libzdb-dev
解决


项目执行cargo check报错:

error[E0271]: type mismatch resolving <impl std::future::Future as std::future::Future>::Output == &mut T -->
/home/tianlang/.cargo/registry/src/github.com-1ecc6299db9ec823/blocking-0.4.6/src/lib.rs:630:40
| 630 | pub async fn get_mut(&mut self) -> &mut T {
| ^^^^^^ expected struct std::boxed::Box, found type parameter
|
= note: expected type &mut std::boxed::Box<T>
found type &mut T
= help: type parameters must be constrained to match other types
= note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
= note: the return type of a function must have a statically known size

从错误信息看是引用的第三方crate blocking里报的错误,我又没升级过依赖库为什么会报错呢? 百思不得其解中…
突然想起来是不是在开发另一个项目时修改了Rust版本,赶紧查看Rust版本:

rustc --version
rustc 1.39.0 (4560ea788 2019-11-04)

额地那个娘啊,这2020年都过去一半了,rust咋还回到2019年了呢?此事必有蹊跷!
赶紧执行 :

rustup update

升级rust ,由于默认访问的国外软件仓库,由于网络原因update了几次都失败了,我这小暴脾气,这得使用国内的软件源啊:

export RUSTUP_DIST_SERVER=“https://mirrors.ustc.edu.cn/rust-static”
reustup update

这次就更新成功了:

rustc --version

rustc 1.44.1 (c7087fe00 2020-06-17)

再次执行cargo check就没问题了
修改rustup/cargo镜像源可以参考博客


在函数中需要根据不同的情况返回不同类型的值,这俩种类型都实现了Responder特征,使用impl Responder定义返回值类型一直报错:

expected opaque type, found struct `actix_http::response::Response  
在网上找到使用Box解决返回实现了相同特征的不同具体类型的方法,可以参考1参考2参考3,后来在actix-web的API文档中发现提供有Either类型,用于解决此种需求

use actix_web::{Either, Error, HttpResponse};

type RegisterResult = Either<HttpResponse, Result<HttpResponse, Error>>;

fn index() -> RegisterResult {
    if is_a_variant() {
        // <- choose left variant
        Either::A(HttpResponse::BadRequest().body("Bad data"))
    } else {
        Either::B(
            // <- Right variant
            Ok(HttpResponse::Ok()
                .content_type("text/html")
                .body("Hello!"))
        )
    }
}

问题解决


遇到个奇怪的问题,使用diesel的find方法查找数据,明明是使用的ID,却查出了多条数据.

pub fn find_article_by_id(conn: &DbConnection, id: &str) -> Result<ArticleModel, Error> {
    use self::tb_article::dsl::*;
    tb_article.find(id).first(conn)
}

还好,当准备使用info!输出日志打印时,报id并没有实现Display特征。参数id明明是&str类型的啊,怎么没实现Display特征呢?
看到

use self::tb_article::dsl:😗;

才想起表tb_article有个字段也叫id,名称一模一样。这就搞明白了,感觉把参数id改名为article_id验证,果然正确了。

pub fn find_article_by_id(conn: &DbConnection, article_id: &str) -> Result<ArticleModel, Error> {
    use self::tb_article::dsl::*;
    tb_article.find(article_id).first(conn)
}

看来使用*号引入还是有风险地.需谨慎!


持续更新中
零基础学新时代编程语言Rust
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一个不安分的程序员

祝您财源广进

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值