Deserializ
in this scopeerror: 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官网文档
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
where
**Conn**: Connection,
Self: ExecuteDsl
查API也没发现泛型参数,最终发现是自己的代码里声明了个泛型Conn,没有用到忘记删掉了。
pub fn add_login_info(conn: &MysqlConnection, new_login_info: &NewLoginInfo) -> Result
在网上看到这个问题:
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 Transform for AuthService
where
S: Service, Error = Error> + 'static,
S::Future: 'static,
B: 'static,
{
type Request = ServiceRequest;
type Response = ServiceResponse;
type Error = Error;
type InitError = ();
type Transform = AuthMiddleware;
type Future = Ready>;
fn new_transform(&self, service: S) -> Self::Future {
ok(AuthMiddleware {
service: Rc::new(RefCell::new(service)),
})
}
}
pub struct AuthMiddleware {
service: Rc>,
}
impl Service for AuthMiddleware
where
S: Service, Error = Error> + 'static,
S::Future: 'static,
B: 'static,
{
type Request = ServiceRequest;
type Response = ServiceResponse;
type Error = Error;
type Future = Pin>>>;
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> {
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
}
})
}
}
部署的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
-->
::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 structstd::boxed::Box
, found type parameter
|
= note: expected type&mut std::boxed::Box
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>;
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 {
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 {
use self::tb_article::dsl::*;
tb_article.find(article_id).first(conn)
}
看来使用*号引入还是有风险地.需谨慎!