重装.net框架_使用 Rust 构建个人博客(1) - Warp 后端框架

bb239616005b0671c6b0de3fe57e7f19.png

需求背景

一个朋友买了一个云主机(就是300元3年的那种)

云主机配置是:

  1. CPU:vCPU 2
  2. 内存:2G
  3. 硬盘:40G
  4. 带宽:1M
  5. 公网IP:1个
  6. 预装的系统是:Windows 2008 R2

这台机器上,跑了一些他自己的东西,虽然机器整体性能不咋的,但是总觉得还可以再“挖掘”一些性能(挤一挤总是会有的),所以还在跑一个自己的博客。

技术选型

最初他问我的时候,我就让他用 WAMP + WordPress,方便、省事儿,而且WP的插件资源一大推,教程也很多。

他说他尝试过,装上了以后,机器莫名卡得厉害(不知道原因)。
把他之前跑的东西都弄慢了,后来导致重装了一次系统。。

好的,这个方案干掉。

要省资源,可以用 Github 的 Pages,托管免费,还可以绑定域名。
试运行了几天以后,朋友反馈,觉得访问速度时快时慢,用户体验不能保证。
(我心想,你博客有啥用户?)

EN,那么再换一个吧。。

那么用静态网站生成器吧,这样,速度和资源,都有保证了。

于是,扔给他了一个链接:Static Site Generators - Top Open Source SSGs | Jamstack

说这里收集了应该是市面上最全的,什么口味儿的都有,包君满意!

链接扔过去了以后,朋友几天没有联系了。

有一天,右下角,他的头像又开始一闪一闪的。。。
有点点不好的预感。

  1. 朋友:我看了几种,后来看得眼睛都花了,最后反而不知道选啥了。
  2. 我:那你可以选比较流行的 Hugo,教程也多
  3. 朋友:嗯,看了。
  4. 我:如何?
  5. 朋友:Windows 用习惯了,看到文字性的配置,就头疼
  6. 我:那我这儿暂时还想不到有啥其它的方案了。
  7. 朋友:那么
  8. 我:啥?
  9. 朋友:我们自己撸一个呢?
  10. 我:啥?(为什么是我们?)
  11. 朋友:最近看了些CSS,想自己试试。(朋友做设计的)
  12. 朋友:之前看的那些框架、静态网站,都好复杂,想自己从 0 开始。慢慢摸索。
  13. 我:(嗯,你学 CSS 从 0 开始,起点是不错的!但是除了 CSS,还有其它一大坨呢。)

正想怎么回复,回头看到一本 Rust 教程,就给朋友说:
我来做后端和前端交互。前端HTML 和 CSS 由你来吧。

最后的方案就是:

后端:Warp + Sqlite + Sled
前端:Yew + 朋友的 HTML 和 CSS

选择的理由?

Rust

我是 2017 年的时候了解到 Rust 的,那时已经发布了 2 年了。

看了它的设计理念、语言设计以及官方教程,我的内心就告诉我,这个就是我需要的语言。

然后,经历了从入门到纠结,再到放弃,再入门到放弃,期望借这个机会再准备入门。

Warp

Rust 不乏优秀的 web 框架,我尝试过 Actix-web -> Tide -> Warp。
Warp 是目前用起最顺手的。

Sqlite

就朋友那点流量,Sqlite 足以应付了

Sled

博客是写少,读多的。用 Sled 来充当一个缓存还是不错的

Yew

用于构建前端的,很方便的将朋友写的 HTML 嵌入到我的代码里。
我就专注于前端与后端交互逻辑了

动工

在那边还在边学边整HTML CSS 的时候,我这里先开始后端的工作。

数据库,有 3 张表

博客内容

CREATE TABLE "blog" (
"id"  INTEGER NOT NULL,
"title"  TEXT(64) NOT NULL,
"markdown_content"  TEXT(20480) NOT NULL,
"parsed_content"  TEXT(65535) NOT NULL,
"tags"  TEXT(256) NOT NULL,
"created_at"  INTEGER NOT NULL,
PRIMARY KEY ("id" ASC)
);

标签数据

CREATE TABLE "blog_tag" (
"id"  INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
"name"  TEXT(32) NOT NULL,
CONSTRAINT "name" UNIQUE ("name" ASC)
);

用户信息(只有朋友一个用户数据,离线初始化进去)

CREATE TABLE "user" (
"id"  INTEGER NOT NULL,
"username"  TEXT(32) NOT NULL,
"password"  TEXT(256) NOT NULL,
PRIMARY KEY ("id")
);

Rust工程

先初始化一个 git 目录,然后创建 workspace,包含 3 个目录

  1. backend 博客后端
  2. frontend 博客前端
  3. common 公共类

进入 backend 目录,创建一个 Rust bin 项目

Cargo.toml引入依赖项

[package]
name = "blog-backend"
version = "0.1.0"
authors = ["Songday <songday@yeah.net>"]
edition = "2018"

[lib]
name = "blog_backend"

[dependencies]
blog-common = { path = "../common" }

ahash = "0.4"
base64 = "0.12"
bytes = "0.5"
chrono = { version = "0.4", features     = ["serde"] }
comrak = "0.8"
futures = "0.3"
hyper = "0.13"
image = { version = "0.23", features = ["jpeg", "png", "gif"] }
lazy_static = "1.4"
lazy-static-include = "3.0"
parking_lot = "0.11"
once_cell = "1.4"
rand = "0.7"
v_htmlescape = "0.10"
subtle = "2"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
sled = "0.34"
sqlx = { version = "0.4.0-beta.1", default-features = false, features = [ "runtime-tokio", "macros", "sqlite"], optional = false }
scrypt = "0.4"
tokio = { version = "0.2", features = ["fs", "io-util", "macros", "rt-core", "rt-threaded", "signal", "time"] }
uuid = { version = "0.8", features = ["v5"] }
urlencoding = "1.1"
warp = "0.2" 

然后,定义一下个人博客的路由。

Warp 最自以为豪的就是它的Filter概念(在定义路由的时候就到的)

Thanks to its Filter system, warp provides these out of the box:

Path routing and parameter extraction
Header requirements and extraction
Query string deserialization
JSON and Form bodies
Multipart form data
Static Files and Directories
Websockets
Access logging
Gzip, Deflate, and Brotli compression

我定义的路由如下:

// 用户登录
let user_login = warp::post()
	.and(warp::path("user"))
	.and(warp::path("login"))
	.and(warp::path::end())
	.and(warp::cookie::optional(var::AUTH_HEADER_NAME))
	.and(warp::body::json::<LoginParams>())
	.and_then(controller::user_login);
// 用户登出
let user_logout = warp::get()
	.and(warp::path("user"))
	.and(warp::path("logout"))
	.and(warp::path::end())
	.and(warp::cookie::optional(var::AUTH_HEADER_NAME))
	.and_then(controller::user_logout);
// 博客列表
let blog_list = warp::get()
	.and(warp::path("blog"))
	.and(warp::path("list"))
	.and(warp::path::param::<u8>())
	.and(warp::path::end())
	.and_then(controller::blog_list);
// 博客标签列表
let blog_tags = warp::get()
	.and(warp::path("blog"))
	.and(warp::path("tags"))
	.and(warp::path::end())
	.and_then(controller::blog_tags);
// 根据博客标签展示博客列表
let blog_list_by_tag = warp::get()
	.and(warp::path("blog"))
	.and(warp::path("tag"))
	.and(warp::path::param::<String>())
	.and(warp::path::param::<u8>())
	.and(warp::path::end())
	.and_then(controller::blog_list_by_tag);
// 保存博客数据
let blog_save = warp::post()
	.and(warp::path("blog"))
	.and(warp::path("save"))
	.and(warp::path::end())
	.and(auth())
	.and(warp::body::json::<NewBlog>())
	.and_then(controller::blog_save);
// 展示某一篇博客文章
let blog_show = warp::get()
	.and(warp::path("blog"))
	.and(warp::path("show"))
	.and(warp::path::param::<u64>())
	.and(warp::path::end())
	.and_then(controller::blog_show);

刚刚定义好了路由,朋友发来了登录页面框架。

我打开看了,还有登录验证码。于是就准备查一下如何让Rust读取字体再在画布上画出来。

这时朋友又发了一个zip,说里面是用于显示验证码的图片。

好吧,省得我去查资料了。

于是,先新增一个显示图片的接口

let verify_image = warp::get()
	.and(warp::path("tool"))
	.and(warp::path("verify-image"))
	.and(warp::path::end())
	.and(warp::cookie::optional(var::AUTH_HEADER_NAME))
	.and_then(controller::verify_image);

画验证图,我用的是imagecrate,效果如下:

a04d43c477c6caff369ff4c2f3b1ce70.png

好了,后端框架搭建得差不多了。

下一篇,我们一起用Yew来搭建前端。

songday:使用 Rust 构建个人博客(2) - Yew 前端框架​zhuanlan.zhihu.com
80589d2146802ec671b4090eb406f319.png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的示例,展示如何使用Rust后端框架Axum来创建一个基本的Web应用程序: 首先,确保您已经安装Rust和Cargo。然后,在您的项目目录中创建一个新的Cargo.toml文件,并添加以下内容: ```toml [package] name = "axum_example" version = "0.1.0" edition = "2021" [dependencies] axum = "0.2" tokio = { version = "1", features = ["full"] } ``` 接下来,创建一个main.rs文件,并添加以下代码: ```rust use axum::{handler::get, Router}; use std::net::SocketAddr; async fn hello_world() -> &'static str { "Hello, world!" } #[tokio::main] async fn main() { // 创建一个Axum应用程序的根路由 let app = Router::new().route("/", get(hello_world)); // 定义服务器的地址和端口 let addr = SocketAddr::from(([127, 0, 0, 1], 3000)); // 运行服务器 axum::Server::bind(&addr) .serve(app.into_make_service()) .await .unwrap(); } ``` 上述代码创建了一个简单的Axum应用程序,该应用程序定义了一个根路由"/",并使用GET方法处理请求。处理程序函数hello_world返回一个字符串"Hello, world!"作为响应。 最后,打开终端,导航到您的项目目录,并运行以下命令来构建和运行应用程序: ``` cargo build cargo run ``` 您应该会看到类似于以下输出: ``` Listening on http://127.0.0.1:3000 ``` 现在,您可以在浏览器中访问http://127.0.0.1:3000,并应该看到"Hello, world!"的响应。 这只是Axum的一个简单示例,您可以根据需要添加更多的路由和处理程序来构建更复杂的应用程序。Axum提供了许多功能和中间件,使您能够处理不同类型的请求和实现复杂的业务逻辑。您可以参考Axum的官方文档以获得更多详细信息和示例代码:https://docs.rs/axum/0.2.5/axum/

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值