前端火箭箭头
In the last few articles, we’ve been exploring the Rocket library for Rust web servers. Last time out, we tried a couple ways to add authentication to our web server. In this last Rocket-specific post, we’ll explore some ideas around frontend templating. This will make it easy for you to serve HTML content to your users!
在最后几篇文章中,我们一直在探索Rust Web服务器的Rocket库。 上次超时时,我们尝试了几种方法来向Web服务器添加身份验证 。 在这最后一个特定于Rocket的文章中,我们将探讨有关前端模板的一些想法。 这将使您轻松为用户提供HTML内容!
To explore the code for this article, head over to the “rocket_template” file on our Github repo! If you’re still new to Rust, you might want to start with some simpler material. Take a look at our Rust Beginners Series as well!
要浏览本文的代码,请转到我们的Github 存储库上的“ rocket_template”文件 ! 如果您还不熟悉Rust,则可能想从一些简单的材料开始。 也来看看我们的Rust初学者系列 !
模板基础 (Templating Basics)
First, let’s understand the basics of HTML templating. When our server serves out a webpage, we return HTML to the user for the browser to render. Consider this simple index page:
首先,让我们了解HTML模板化的基础知识。 当我们的服务器提供网页服务时,我们将HTML返回给用户,以供浏览器呈现。 考虑以下简单的索引页:
<html>
<head></head>
<body>
<p> Welcome to the site!</p>
</body>
</html>
But of course, each user should see some kind of custom content. For example, in our greeting, we might want to give the user’s name. In an HTML template, we’ll create a variable or sorts in our HTML, delineated by braces:
但是,当然,每个用户都应该看到某种自定义内容。 例如,在问候语中,我们可能要提供用户名。 在HTML 模板中 ,我们将在HTML中创建一个变量或对它们进行排序,并用大括号表示:
<html>
<head></head>
<body>
<p> Welcome to the site {{name}}!</p>
</body>
</html>
Now before we return the HTML to the user, we want to perform a substitution. Where we find the variable {{name}}
, we should replace it with the user's name, which our server should know.
现在,在我们将HTML返回给用户之前,我们要执行替换。 在找到变量{{name}}
,应将其替换为服务器应知道的用户名。
There are many different libraries that do this, often through Javascript. But in Rust, it turns out the Rocket library has a couple easy templating integrations. One option is Tera, which was specifically designed for Rust. Another option is Handlebars, which is more native to Javascript, but also has a Rocket integration. The substitutions in this article are simple, so there’s not actually much of a difference for us.
有许多不同的库通常通过Javascript执行此操作。 但事实证明,在Rust中,Rocket库具有几个简单的模板集成。 一种选择是Tera ,它是专为Rust设计的。 另一个选择是Handlebars ,它更原始于Javascript,但也具有Rocket集成。 本文中的替换很简单,因此对我们而言实际上没有太大区别。
返回模板 (Returning a Template)
So how do we configure our server to return this HTML data? To start, we have to attach a “Fairing” to our server, specifically for the Template
library. A Fairing is a server-wide piece of middleware. This is how we can allow our endpoints to return templates:
那么,我们如何配置服务器以返回此HTML数据? 首先,我们必须在服务器上附加一个“ Fairing”,专门用于Template
库。 Fairing是服务器范围的中间件。 这是我们允许端点返回模板的方式:
use rocket_contrib::templates::Template;fn main() {
rocket::ignite()
.mount("/", routes![index, get_user])
.attach(Template::fairing())
.launch();
}
Now we can make our index
endpoint. It has no inputs, and it will return Rocket's Template
type.
现在我们可以建立index
端点了。 它没有输入,它将返回Rocket的Template
类型。
#[get("/")]
fn index() -> Template {
...
}
We have two tasks now. First, we have to construct our context. This can be any “map-like” type with string information. We’ll use a HashMap
, populating the name
value.
现在我们有两个任务。 首先,我们必须构建我们的环境。 这可以是任何带有字符串信息的“类似于地图的”类型。 我们将使用HashMap
,填充name
值。
#[get("/")]
fn index() -> Template {
let context: HashMap<&str, &str> = [("name", "Jonathan")]
.iter().cloned().collect();
...
}
Now we have to render
our template. Let's suppose we have a "templates" directory at the root of our project. We can put the template we wrote above in the "index.hbs" file. When we call the render
function, we just give the name of our template and pass the context
!
现在我们必须render
我们的模板。 假设我们在项目的根目录下有一个“ templates”目录。 我们可以将上面编写的模板放在“ index.hbs”文件中。 当我们调用render
函数时,我们只给出模板的名称并传递context
!
#[get("/")]
fn index() -> Template {
let context: HashMap<&str, &str> = [("name", "Jonathan")]
.iter().cloned().collect();
Template::render("index", &context)
}
包括静态资产 (Including Static Assets)
Rocket also makes it quite easy to include static assets as part of our routing system. We just have to mount
the static
route to the desired prefix when launching our server:
Rocket还使将静态资产作为路由系统的一部分变得非常容易。 启动服务器时,我们只需要将static
路由mount
到所需的前缀即可:
fn main() {
rocket::ignite()
.mount("/static", StaticFiles::from("static"))
.mount("/", routes![index, get_user])
.attach(Template::fairing())
.launch();
}
Now any request to a /static/...
endpoint will return the corresponding file in the "static" directory of our project. Suppose we have this styles.css
file:
现在,对/static/...
端点的任何请求都将在我们项目的“静态”目录中返回相应的文件。 假设我们有这个styles.css
文件:
p {
color: red;
}
We can then link to this file in our index template:
然后,我们可以在索引模板中链接到该文件:
<html>
<head>
<link rel="stylesheet" type="text/css" href="static/styles.css"/>
</head>
<body>
<p> Welcome to the site {{name}}!</p>
</body>
</html>
Now when we fetch our index, we’ll see that the text on the page is red!
现在,当我们获取索引时,我们将看到页面上的文本为红色!
循环进入我们的数据库 (Looping in our Database)
Now for one last piece of integration with our database. Let’s make a page that will show a user their basic information. This starts with a simple template:
现在是与数据库的最后一步集成。 让我们制作一个页面,向用户显示其基本信息。 这从一个简单的模板开始:
<!-- templates/user.hbs -->
<html>
<head></head>
<body>
<p> User name: {{name}}</p>
<br>
<p> User email: {{email}}</p>
<br>
<p> User name: {{age}}</p>
</body>
</html>
We’ll compose an endpoint that takes the user’s ID as an input and fetches the user from the database:
我们将组成一个端点,该端点将用户的ID作为输入并从数据库中获取用户:
#[get("/users/<uid>")]
fn get_user(uid: i32) -> Template {
let maybe_user = fetch_user_by_id(&local_conn_string(), uid);
...
}
Now we need to build our context from the user information. This will require a match
statement on the resulting user. We'll use Unknown
for the fields if the user doesn't exist.
现在,我们需要根据用户信息来构建上下文。 这将要求对结果用户进行match
声明。 如果用户不存在,我们将对字段使用“ Unknown
”。
#[get("/users/<uid>")]
fn get_user(uid: i32) -> Template {
let maybe_user = fetch_user_by_id(&local_conn_string(), uid);
let context: HashMap<&str, String> = {
match maybe_user {
Some(u) =>
[ ("name", u.name.clone())
, ("email", u.email.clone())
, ("age", u.age.to_string())
].iter().cloned().collect(),
None =>
[ ("name", String::from("Unknown"))
, ("email", String::from("Unknown"))
, ("age", String::from("Unknown"))
].iter().cloned().collect()
}
};
Template::render("user", &context)
}
And to wrap it up, we’ll render
the "user" template! Now when users get directed to the page for their user ID, they'll see their information!
最后,我们将render
“用户”模板! 现在,当用户进入页面获取其用户ID时,他们将看到其信息!
结论 (Conclusion)
Next week, we’ll go back to some of our authentication code. But we’ll do so with the goal of exploring a more universal Rust idea. We’ll see how functors and monads still find a home in Rust. We’ll explore the functions that allow us to clean up heavy conditional code just as we could in Haskell.
下周,我们将返回一些身份验证代码。 但是我们将以探索更通用的Rust思想为目标。 我们将看到函子和单子仍然如何在Rust中找到家。 我们将探索使我们能够像在Haskell中那样清理沉重的条件代码的功能。
For a more in-depth introduction to Rust basics, be sure to take a look at our Rust Video Tutorial!
要更深入地介绍Rust基础知识,请务必查看我们的Rust Video Tutorial !
翻译自: https://medium.com/@james_32022/rocket-frontend-templates-and-static-assets-5b6d04243a08
前端火箭箭头