域名 AXUM.RS 将于2025年10月到期。我们无意再对其进行续费,我们希望你能够接续这个域名,让更多 AXUM 开发者继续受益。
  • 方案1️⃣AXUM.RS 域名 = 3000
  • 方案2️⃣方案1️⃣ + 本站所有专题原始 Markdown 文档 = 5000
  • 方案3️⃣方案2️⃣ + 本站原始数据库 = 5500
如果你有意接续这份 AXUM 情怀,请与我们取得联系。
说明:
  1. 如果有人购买 AXUM.RS 域名(方案1️⃣),或者该域名到期,本站将启用新的免费域名继续提供服务。
  2. 如果有人购买了 AXUM.RS 域名,且同时购买了内容和/或数据库(方案2️⃣/方案3️⃣),本站将关闭。届时我们或许会以另一种方式与你再相遇。

总结与代码清理

目前为止,我们的短链接服务基本已经完成了。但有一些地方不完善,同时有些警告没有处理掉。

本章代码在06/清理分支。

本章代码在06/清理分支。

AppError 的处理

因为我们的 MsgTemplate 已经提供了 err() 方法,所以在 AppError 可以直接调用该方法:

let tmpl = MsgTemplate::err(msg.clone());
let html = tmpl.render().unwrap_or(msg);
Html(html).into_response()

另外,为了处理保留字的检测,我们还要加上:

pub fn reserved_word(word: &str) -> Self {
    let msg = format!("{}是保留字", word);
    Self::from_str(&msg, AppErrorType::ReservedWord)
}

AppErrorType 的处理

当然,AppErrorType 也要加上保留字的枚举项:

pub enum AppErrorType {
    //...
    ReservedWord,
}

MsgTemplate::ok() 方法删除,因为没有任何地方用到它。

为了便于显示添加成功的短链接,我们将index_action()的跳转改为 index()

index_action()

let redirect_url = format!("/?id={}", result.id);
Ok(redirect(&redirect_url))

另外,为了检测生成的短链接是否是保留字(虽然概率极小,在开启自定义短链接时,这个检测非常有必要),我们还需要增加:

if (&state).short_url_cfg.in_reserved_words(&id) {
    return Err(AppError::reserved_word(&id));
};

index()

#[derive(Deserialize)]
pub struct IndexArgs {
    pub id: Option<String>,
}
pub async fn index(
    Extension(state): Extension<AppState>,
    Query(args): Query<IndexArgs>,
) -> HandlerHtmlResult {
    let handler_name = "index";
    let tmpl = IndexTemplate {
        id: args.id.clone(),
        short_url_domain: state.short_url_cfg.domain.clone(),
    };
    render(tmpl).map_err(log_error(handler_name.to_string()))
}

模板结构体

对应的,IndexTemplate 也要进行处理:

#[derive(Template)]
#[template(path = "index.html")]
pub struct IndexTemplate {
    pub id: Option<String>,
    pub short_url_domain: String,
}
impl IndexTemplate {
    pub fn id(&self) -> String {
        self.id.clone().unwrap_or("".to_string())
    }
}

模板文件

<h1>创建你的短网址</h1>
{%if !self.id().is_empty() %}
<div class="alert alert-info my-3">
  短链接创建成功:<a href="//{{short_url_domain}}/{{self.id()}}" target="_blank"
    >{{short_url_domain}}/{{self.id()}}</a
  >
</div>
{% endif%}
<form action="/" method="post" autocomplete="off"></form>

核心算法的处理

把两个带_with_seed 后缀的函数加上 #[allow(unused)]

数据库的处理

本专题带你实现了一个短链接服务。

  • 短链接算法:使用 murmur3 将原始链接转成 32 位的正整数哈希值,然后将这个哈希值转成字符形式的 base62, 这个就是我们的短链接

  • 模板:本专题使用了模板引擎

  • PostgreSQL:当然,本专题少不了数据库

  • 静态资源:为了配合模板引用的静态文件,我们加上了静态资源的处理

  • 配置文件、日志:这两个“标配”自然少不了

短链接算法:使用 murmur3 将原始链接转成 32 位的正整数哈希值,然后将这个哈希值转成字符形式的 base62, 这个就是我们的短链接

模板:本专题使用了模板引擎

PostgreSQL:当然,本专题少不了数据库

静态资源:为了配合模板引用的静态文件,我们加上了静态资源的处理

配置文件、日志:这两个“标配”自然少不了

要查看完整内容,请先登录