1
0
mirror of https://github.com/actix/actix-website synced 2024-12-12 07:53:10 +01:00

clean code add new cn site

This commit is contained in:
krircc 2018-06-25 22:52:00 +08:00
parent cf8f8c9b3e
commit bc5989fa38
38 changed files with 3 additions and 3349 deletions

View File

@ -13,10 +13,6 @@ baseURL = "https://actix.rs"
languageCode = "en-US" languageCode = "en-US"
languageName = "English" languageName = "English"
weight = 1 weight = 1
[languages.cn]
languageCode = "zh-CN"
languageName = "中文"
weight = 2
[params] [params]
actixVersion = "0.5" actixVersion = "0.5"

View File

@ -1,3 +0,0 @@
---
title: Actix中文
---

View File

@ -1,8 +0,0 @@
---
title: 旧
description: 2018-01-01
menu: blog_2018
weight: 999
---
# Title

View File

@ -1,8 +0,0 @@
---
title: 新
description: 2018-06-11
menu: blog_2018
weight: 998
---
# Title

View File

@ -1,10 +0,0 @@
---
title: 博客
description: 快乐的Actix之旅
menu:
blog_intro:
name: 欢迎
weight: 1
---
欢迎开始快乐的Actix之旅 你可以从左侧的时间点选择开始。

View File

@ -1,18 +0,0 @@
---
title: 源码
description: 浏览,下载源码
---
# 浏览源码
所有的Actix代码都是开源的可以在我们的github组织中找到: [actix
on github](https://github.com/actix)
以下是最重要的项目以及与其github存储库和相关资源的链接:
* [actix](https://github.com/actix/actix) ([issues](https://github.com/actix/actix/issues), [ci](https://travis-ci.org/actix/actix), [crate](https://crates.io/crates/actix), [api docs](https://docs.rs/actix))
* [actix-web](https://github.com/actix/actix-web) ([issues](https://github.com/actix/actix-web/issues), [ci](https://travis-ci.org/actix/actix-web), [crate](https://crates.io/crates/actix-web), [api docs](https://docs.rs/actix-web))
* [example code](https://github.com/actix/examples)
* [this website](https://github.com/actix/actix-website)
Actix在MIT和Apache 2下获得双重许可。[许可证文本](license/).

View File

@ -1,201 +0,0 @@
---
title: License
---
Actix is dual licensed under MIT and Apache licenses.
# MIT License
Copyright (c) 2017 Nikolay Kim
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
Software without restriction, including without
limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software
is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice
shall be included in all copies or substantial portions
of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
# Apache License
_Version 2.0, January 2004_
http://www.apache.org/licenses/
### Terms and Conditions for use, reproduction, and distribution
#### 1. Definitions
“License” shall mean the terms and conditions for use, reproduction, and
distribution as defined by Sections 1 through 9 of this document.
“Licensor” shall mean the copyright owner or entity authorized by the copyright
owner that is granting the License.
“Legal Entity” shall mean the union of the acting entity and all other entities
that control, are controlled by, or are under common control with that entity.
For the purposes of this definition, “control” means **(i)** the power, direct or
indirect, to cause the direction or management of such entity, whether by
contract or otherwise, or **(ii)** ownership of fifty percent (50%) or more of the
outstanding shares, or **(iii)** beneficial ownership of such entity.
“You” (or “Your”) shall mean an individual or Legal Entity exercising
permissions granted by this License.
“Source” form shall mean the preferred form for making modifications, including
but not limited to software source code, documentation source, and configuration
files.
“Object” form shall mean any form resulting from mechanical transformation or
translation of a Source form, including but not limited to compiled object code,
generated documentation, and conversions to other media types.
“Work” shall mean the work of authorship, whether in Source or Object form, made
available under the License, as indicated by a copyright notice that is included
in or attached to the work (an example is provided in the Appendix below).
“Derivative Works” shall mean any work, whether in Source or Object form, that
is based on (or derived from) the Work and for which the editorial revisions,
annotations, elaborations, or other modifications represent, as a whole, an
original work of authorship. For the purposes of this License, Derivative Works
shall not include works that remain separable from, or merely link (or bind by
name) to the interfaces of, the Work and Derivative Works thereof.
“Contribution” shall mean any work of authorship, including the original version
of the Work and any modifications or additions to that Work or Derivative Works
thereof, that is intentionally submitted to Licensor for inclusion in the Work
by the copyright owner or by an individual or Legal Entity authorized to submit
on behalf of the copyright owner. For the purposes of this definition,
“submitted” means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems, and
issue tracking systems that are managed by, or on behalf of, the Licensor for
the purpose of discussing and improving the Work, but excluding communication
that is conspicuously marked or otherwise designated in writing by the copyright
owner as “Not a Contribution.”
“Contributor” shall mean Licensor and any individual or Legal Entity on behalf
of whom a Contribution has been received by Licensor and subsequently
incorporated within the Work.
#### 2. Grant of Copyright License
Subject to the terms and conditions of this License, each Contributor hereby
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
irrevocable copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the Work and such
Derivative Works in Source or Object form.
#### 3. Grant of Patent License
Subject to the terms and conditions of this License, each Contributor hereby
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
irrevocable (except as stated in this section) patent license to make, have
made, use, offer to sell, sell, import, and otherwise transfer the Work, where
such license applies only to those patent claims licensable by such Contributor
that are necessarily infringed by their Contribution(s) alone or by combination
of their Contribution(s) with the Work to which such Contribution(s) was
submitted. If You institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work or a
Contribution incorporated within the Work constitutes direct or contributory
patent infringement, then any patent licenses granted to You under this License
for that Work shall terminate as of the date such litigation is filed.
#### 4. Redistribution
You may reproduce and distribute copies of the Work or Derivative Works thereof
in any medium, with or without modifications, and in Source or Object form,
provided that You meet the following conditions:
* **(a)** You must give any other recipients of the Work or Derivative Works a copy of
this License; and
* **(b)** You must cause any modified files to carry prominent notices stating that You
changed the files; and
* **(c)** You must retain, in the Source form of any Derivative Works that You distribute,
all copyright, patent, trademark, and attribution notices from the Source form
of the Work, excluding those notices that do not pertain to any part of the
Derivative Works; and
* **(d)** If the Work includes a “NOTICE” text file as part of its distribution, then any
Derivative Works that You distribute must include a readable copy of the
attribution notices contained within such NOTICE file, excluding those notices
that do not pertain to any part of the Derivative Works, in at least one of the
following places: within a NOTICE text file distributed as part of the
Derivative Works; within the Source form or documentation, if provided along
with the Derivative Works; or, within a display generated by the Derivative
Works, if and wherever such third-party notices normally appear. The contents of
the NOTICE file are for informational purposes only and do not modify the
License. You may add Your own attribution notices within Derivative Works that
You distribute, alongside or as an addendum to the NOTICE text from the Work,
provided that such additional attribution notices cannot be construed as
modifying the License.
You may add Your own copyright statement to Your modifications and may provide
additional or different license terms and conditions for use, reproduction, or
distribution of Your modifications, or for any such Derivative Works as a whole,
provided Your use, reproduction, and distribution of the Work otherwise complies
with the conditions stated in this License.
#### 5. Submission of Contributions
Unless You explicitly state otherwise, any Contribution intentionally submitted
for inclusion in the Work by You to the Licensor shall be under the terms and
conditions of this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify the terms of
any separate license agreement you may have executed with Licensor regarding
such Contributions.
#### 6. Trademarks
This License does not grant permission to use the trade names, trademarks,
service marks, or product names of the Licensor, except as required for
reasonable and customary use in describing the origin of the Work and
reproducing the content of the NOTICE file.
#### 7. Disclaimer of Warranty
Unless required by applicable law or agreed to in writing, Licensor provides the
Work (and each Contributor provides its Contributions) on an “AS IS” BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
including, without limitation, any warranties or conditions of TITLE,
NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
solely responsible for determining the appropriateness of using or
redistributing the Work and assume any risks associated with Your exercise of
permissions under this License.
#### 8. Limitation of Liability
In no event and under no legal theory, whether in tort (including negligence),
contract, or otherwise, unless required by applicable law (such as deliberate
and grossly negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special, incidental,
or consequential damages of any character arising as a result of this License or
out of the use or inability to use the Work (including but not limited to
damages for loss of goodwill, work stoppage, computer failure or malfunction, or
any and all other commercial damages or losses), even if such Contributor has
been advised of the possibility of such damages.
#### 9. Accepting Warranty or Additional Liability
While redistributing the Work or Derivative Works thereof, You may choose to
offer, and charge a fee for, acceptance of support, warranty, indemnity, or
other liability obligations and/or rights consistent with this License. However,
in accepting such obligations, You may act only on Your own behalf and on Your
sole responsibility, not on behalf of any other Contributor, and only if You
agree to indemnify, defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason of your
accepting any such warranty or additional liability.

View File

@ -1,29 +0,0 @@
---
title: 社区
description: 人生中最美好的事物就是分享
---
# 加入我们
想与其他人讨论问题吗Actix的你最好的起点是:
- [gitter](https://gitter.im/actix/actix)频道
- [reddit](https://www.reddit.com/r/actix/)社区
- QQ群570065685
如果你发现了一个bug最好直接去
[github](https://github.com/actix) . 有2个主要仓库:
- [actix](https://github.com/actix/actix) Rust强大的actor系统
- [actix-web](https://github.com/actix/actix-web) Rust高水平Web框架。
我们是一个热情的社区,所以不要害怕参与. [我们遵守的行为准则](coc/).
# 案例
如果你还没有准备好,这里有一些案例
- [OUISRC/muro](https://github.com/OUISRC/muro) : The interest and community for internet .(reddit clone)
- [swipe-app/swipe-server](https://github.com/swipe-app/swipe-server) : Swipe app api with actix-web and graphql
- [yew-actix-protobuf-sample](https://github.com/havarnov/yew-actix-protobuf-sample) : web app written in yew and actix.
- [yinyanlv/partner](https://github.com/yinyanlv/partner) : 一个私人生活辅助系统前后端分离。前端angular6+material-design后端actix-webdieselmysqlredis
- [yinyanlv/partner-client](https://github.com/yinyanlv/partner-client) : partner项目的前端仓库

View File

@ -1,49 +0,0 @@
---
title: Contributor Covenant Code of Conduct
description:
---
# Our Pledge
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
# Our Standards
Examples of behavior that contributes to creating a positive environment include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a professional setting
# Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
# Scope
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
# Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at fafhrd91@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
# Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/

View File

@ -1,40 +0,0 @@
---
title: 安装
menu: docs_intro
weight: 110
---
# 安装 Rust
既然actix-web是一个Rust框架你需要Rust来使用它。如果您还没有它我们建议您使用rustup来管理您的Rust安装。该[官员Rust指南](https://doc.rust-lang.org/book/second-edition/ch01-01-installation.html) 有精彩的入门部分。
我们目前至少需要Rust 1.24因此请确保您运行的rustup update 是最新且最好的Rust版本。特别是本指南将假定您实际运行Rust 1.26或更高版本。
# 安装 `actix-web`
感谢Rust的cargo包管理您不需要明确安装 actix-web。只需要声明依赖就行了。对于想要使用actix-web的开发版本的情况您可以直接依赖git存储库。
Release版本
```ini
[dependencies]
actix-web = "{{< actix-version "actix-web" >}}"
```
Development 版本:
```ini
[dependencies]
actix-web = { git = "https://github.com/actix/actix-web" }
```
# 深入
在这里有两条你可以选择的路径。你可以沿着指南或者如果你非常不耐烦,你可能想看看我们 广泛的[示例库](https://github.com/actix/examples)并运行包含的示例。这里举例说明如何运行包含的basics 示例:
```
git clone https://github.com/actix/examples
cd examples/basics
cargo run
```

View File

@ -1,14 +0,0 @@
---
title: 文档
description: 指导您使用actix构建应用程序
menu:
docs_intro:
name: 欢迎
weight: 10
---
# 欢迎来到Actix
Actix是您用Rust开发Web服务的大门本文档将引导您。
本文档目前主要介绍actix-web构建在[actix](https://docs.rs/actix)的actor框架和 [Tokio](https://tokio.rs/)异步IO系统之上的高级Web框架。这是从API稳定的角度出发。

View File

@ -1,75 +0,0 @@
---
title: 应用
menu: docs_basics
weight: 140
---
# 编写应用
actix-web提供了用Rust构建Web服务器和应用程序的各种基础类型。它提供了路由中间件请求的预处理响应的后处理websocket协议处理multipart流等等。
所有actix web服务器都是围绕该App实例构建的。它用于为资源和中间件注册路由。它还存储同一应用程序中所有处理程序之间共享的应用程序状态
应用程序充当所有路由的命名空间即特定应用程序的所有路由具有相同的url路径前缀。应用程序前缀总是包含一个前导的“/”斜杠。如果提供的前缀不包含前导斜杠,则会自动插入。前缀应该由路径值组成。
对于具有前缀的应用程序/app与任何请求路径中有/app/app/或/app/test匹配; 然而,路径/application不匹配。
{{< include-example example="application" section="make_app" >}}
在此示例中,将创建具有/app前缀和index.html资源的应用。该资源可通过/app/index.html路径获得。
>有关更多信息,请查看[URL Dispatch](../url-dispatch)部分。
一台服务器服务多个应用:
{{< include-example example="application" section="run_server" >}}
所有/app1请求路由到第一个应用程序/app2到第二个所有其他到第三个。 应用程序根据注册顺序进行匹配。如果具有更通用的前缀的应用程序在不通用的应用程序之前注册它将有效地阻止较不通用的应用程序匹配。例如如果App将前缀"/"注册为第一个应用程序,它将匹配所有传入的请求。
## 状态
同一应用程序内应用程序状态被所有路由和资源共享。当使用http actor时状态可以HttpRequest::state()作为只读访问但内部可变性RefCell可用于实现状态可变性。状态也可用于路由匹配谓词和中间件。
我们来编写一个使用共享状态的简单应用程序。我们打算将请求计数存储在状态中:
{{< include-example example="application" file="state.rs" section="setup" >}}
应用程序需要通过初始化状态来初始化。
{{< include-example example="application" file="state.rs" section="make_app" >}}
> **注意**http服务器接受应用程序工厂而不是应用程序实例。Http服务器为每个线程构造一个应用程序实例因此应用程序状态必须多次构建。如果你想在不同线程之间共享状态应该使用共享对象例如Arc。应用程序状态并不需要是Send和Sync但应用程序的工厂必须是Send+ Sync。
要启动以前的应用程序,请为其创建闭包:
{{< include-example example="application" file="state.rs" section="start_app" >}}
## 结合不同状态的应用程序
将多个应用程序与不同状态组合也是可能的。
[server::new](https://docs.rs/actix-web/*/actix_web/server/fn.new.html)需要handler具有单一类型。
使用[App::boxed](https://docs.rs/actix-web/*/actix_web/struct.App.html#method.boxed)方法可以轻松解决此限制该方法可将App转换为boxed trait object。
{{< include-example example="application" file="state.rs" section="combine" >}}
## 使用应用程序前缀来组合应用程序
该App::prefix()方法允许设置特定的应用程序前缀。此前缀表示将添加到所有资源模式的资源前缀通过资源配置。 这可以用来帮助挂载一组路由在不同的
地点比所包含的可调用作者的意图仍保持原样资源名称。
例如:
{{< include-example example="url-dispatch" file="prefix.rs" section="prefix" >}}
在上面的示例中,`show_users`路由将具有/users/show的有效路由模式 而不是/ show因为应用程序的前缀参数将预先添加到该模式。只有当URL路径为/users/show并且HttpRequest.url_for()路由名称show_users调用该函数时路由才会匹配它将生成具有相同路径的URL。
## 应用程序谓词和虚拟主机
您可以将谓词看作一个接受请求对象引用并返回true或false的简单函数。形式上谓词是实现[`Predicate`](https://docs.rs/actix-web/0.6.10/actix_web/pred/trait.Predicate.html) trait的任何对象 。Actix提供了几个谓词你可以检查 API文档的[functions section](https://docs.rs/actix-web/0.6.10/actix_web/pred/index.html#functions)部分。
任何这些谓词都可以用于App::filter()方法。提供的谓词之一是Host它可以根据请求的主机信息用作应用程序的过滤器。
{{< include-example example="application" file="vh.rs" section="vh" >}}

View File

@ -1,65 +0,0 @@
---
title: 自动重加载
menu: docs_patterns
weight: 1000
---
# 自动重新加载开发服务器
在开发过程中cargo自动重新编译变更代码会非常方便。这可以通过使用[cargo-watch](https://github.com/passcod/cargo-watch)来完成 。由于actix应用程序通常会绑定到端口以侦听传入的HTTP请求因此将它与[listenfd](https://crates.io/crates/listenfd)和[systemfd](https://github.com/mitsuhiko/systemfd)实用程序结合起来以确保套接字在应用程序编译和重新加载时保持打开状态是有意义的。
`systemfd`将打开一个套接字并将其传递给`cargo-watch`以监视更改然后调用编译器并运行您的actix应用程序。actix应用程序将使用`listenfd`获取 `systemfd`打开的套接字systemfd。
## 需要的二进制文件
对于自动重新加载体验,您需要安装`cargo-watch`和 `systemfd`。两者都用`cargo install`安装
```
cargo install systemfd cargo-watch
```
## 修改代码
此外您需要稍微修改您的actix应用程序以便它可以获取由`systemfd`打开的外部套接字。将`listenfd`添加到您的应用依赖项中:
```ini
[dependencices]
listenfd = "0.3"
```
然后修改您的服务器代码以仅以`bind`作为回调:
```rust
extern crate listenfd;
use listenfd::ListenFd;
use actix_web::{server, App, HttpRequest, Responder};
fn index(_req: HttpRequest) -> impl Responder {
"Hello World!"
}
fn main() {
let mut listenfd = ListenFd::from_env();
let mut server = server::new(|| {
App::new()
.resource("/", |r| r.f(index))
});
server = if let Some(l) = listenfd.take_tcp_listener(0).unwrap() {
server.listen(l)
} else {
server.bind("127.0.0.1:3000").unwrap()
};
server.run();
}
```
## 运行服务器
现在运行开发服务器调用这个命令:
```
systemfd --no-pid -s http::3000 -- cargo watch -x run
```

View File

@ -1,119 +0,0 @@
---
title: 数据库
menu: docs_patterns
weight: 1010
---
# Diesel
目前Diesel 1.0不支持异步操作但可以将actix同步actor系统用作数据库接口API。从技术上讲同步actor是worker风格的actor。
多个同步actors可以并行运行并处理来自同一队列的消息。同步actors以mpsc模式工作。
我们来创建一个简单的数据库api它可以将一个新的 user row插入到SQLite表中。我们必须定义一个同步actor和该actor将使用的连接。其他数据库可以使用相同的方法。
```rust
use actix::prelude::*;
struct DbExecutor(SqliteConnection);
impl Actor for DbExecutor {
type Context = SyncContext<Self>;
}
```
这是我们actor的定义。现在我们必须定义创建用户消息和响应。
```rust
struct CreateUser {
name: String,
}
impl Message for CreateUser {
type Result = Result<User, Error>;
}
```
我们可以向演员发送`CreateUser`消息`DbExecutor` actor因此我们将收到一个 `User`实例。接下来,我们必须为此消息定义处理程序实现。
```rust
impl Handler<CreateUser> for DbExecutor {
type Result = Result<User, Error>;
fn handle(&mut self, msg: CreateUser, _: &mut Self::Context) -> Self::Result
{
use self::schema::users::dsl::*;
// Create insertion model
let uuid = format!("{}", uuid::Uuid::new_v4());
let new_user = models::NewUser {
id: &uuid,
name: &msg.name,
};
// normal diesel operations
diesel::insert_into(users)
.values(&new_user)
.execute(&self.0)
.expect("Error inserting person");
let mut items = users
.filter(id.eq(&uuid))
.load::<models::User>(&self.0)
.expect("Error loading person");
Ok(items.pop().unwrap())
}
}
```
仅此而已现在我们可以使用来在于任何http处理程序或中间件的DbExecutor actor。我们需要的只是启动DbExecutor actors并将地址存储在http处理程序可以访问的状态中。
```rust
/// This is state where we will store *DbExecutor* address.
struct State {
db: Addr<Syn, DbExecutor>,
}
fn main() {
let sys = actix::System::new("diesel-example");
// Start 3 parallel db executors
let addr = SyncArbiter::start(3, || {
DbExecutor(SqliteConnection::establish("test.db").unwrap())
});
// Start http server
HttpServer::new(move || {
App::with_state(State{db: addr.clone()})
.resource("/{name}", |r| r.method(Method::GET).a(index))})
.bind("127.0.0.1:8080").unwrap()
.start().unwrap();
println!("Started http server: 127.0.0.1:8080");
let _ = sys.run();
}
```
我们将在请求处理程序中使用该地址。处理程序返回future对象; 因此,我们异步接收响应消息。`Route::a()`必须用于异步处理注册。
```rust
/// Async handler
fn index(req: HttpRequest<State>) -> Box<Future<Item=HttpResponse, Error=Error>> {
let name = &req.match_info()["name"];
// Send message to `DbExecutor` actor
req.state().db.send(CreateUser{name: name.to_owned()})
.from_err()
.and_then(|res| {
match res {
Ok(user) => Ok(HttpResponse::Ok().json(user)),
Err(_) => Ok(HttpResponse::InternalServerError().into())
}
})
.responder()
}
```
[diesel directory](https://github.com/actix/examples/tree/master/diesel/)提供了一个完整的示例。
有关同步actors的更多信息可以在[actix documentation](https://docs.rs/actix/0.5.0/actix/sync/index.html)文档中找到 。

View File

@ -1,238 +0,0 @@
---
title: Errors
menu: docs_advanced
weight: 180
---
# Errors
Actix uses its own [`actix_web::error::Error`][actixerror] type and
[`actix_web::error::ResponseError`][responseerror] trait for error handling
from web handlers.
If a handler returns an `Error` (referring to the [general Rust trait
`std::error::Error`][stderror]) in a `Result` that also implements the
`ResponseError` trait, actix will render that error as an HTTP response.
`ResponseError` has a single function called `error_response()` that returns
`HttpResponse`:
```rust
pub trait ResponseError: Fail {
fn error_response(&self) -> HttpResponse {
HttpResponse::new(StatusCode::INTERNAL_SERVER_ERROR)
}
}
```
A `Responder` coerces compatible `Result`s into HTTP responses:
```rust
impl<T: Responder, E: Into<Error>> Responder for Result<T, E>
```
`Error` in the code above is actix's error definition, and any errors that
implement `ResponseError` can be converted to one automatically.
Actix-web provides `ResponseError` implementations for some common non-actix
errors. For example, if a handler responds with an `io::Error`, that error is
converted into an `HttpInternalServerError`:
```rust
use std::io;
fn index(req: HttpRequest) -> io::Result<fs::NamedFile> {
Ok(fs::NamedFile::open("static/index.html")?)
}
```
See [the actix-web API documentation](responseerrorimpls) for a full list of
foreign implementations for `ResponseError`.
## An example of a custom error response
Here's an example implementation for `ResponseError`:
```rust
use actix_web::*;
#[derive(Fail, Debug)]
#[fail(display="my error")]
struct MyError {
name: &'static str
}
// Use default implementation for `error_response()` method
impl error::ResponseError for MyError {}
fn index(req: HttpRequest) -> Result<&'static str, MyError> {
Err(MyError{name: "test"})
}
```
`ResponseError` has a default implementation for `error_response()` that will
render a *500* (internal server error), and that's what will happen when the
`index` handler executes above.
Override `error_response()` to produce more useful results:
```rust
#[macro_use] extern crate failure;
use actix_web::{App, HttpRequest, HttpResponse, http, error};
#[derive(Fail, Debug)]
enum MyError {
#[fail(display="internal error")]
InternalError,
#[fail(display="bad request")]
BadClientData,
#[fail(display="timeout")]
Timeout,
}
impl error::ResponseError for MyError {
fn error_response(&self) -> HttpResponse {
match *self {
MyError::InternalError => HttpResponse::new(
http::StatusCode::INTERNAL_SERVER_ERROR),
MyError::BadClientData => HttpResponse::new(
http::StatusCode::BAD_REQUEST),
MyError::Timeout => HttpResponse::new(
http::StatusCode::GATEWAY_TIMEOUT),
}
}
}
fn index(req: HttpRequest) -> Result<&'static str, MyError> {
Err(MyError::BadClientData)
}
```
# Error helpers
Actix provides a set of error helper functions that are useful for generating
specific HTTP error codes from other errors. Here we convert `MyError`, which
doesn't implement the `ResponseError` trait, to a *400* (bad request) using
`map_err`:
```rust
# extern crate actix_web;
use actix_web::*;
#[derive(Debug)]
struct MyError {
name: &'static str
}
fn index(req: HttpRequest) -> Result<&'static str> {
let result: Result<&'static str, MyError> = Err(MyError{name: "test"});
Ok(result.map_err(|e| error::ErrorBadRequest(e.name))?)
}
```
See the [API documentation for actix-web's `error` module][errorhelpers] for a
full list of available error helpers.
# Compatibility with failure
Actix-web provides automatic compatibility with the [failure] library so that
errors deriving `fail` will be converted automatically to an actix error. Keep
in mind that those errors will render with the default *500* status code unless you
also provide your own `error_response()` implementation for them.
# Error logging
Actix logs all errors at the `WARN` log level. If an application's log level is
set to `DEBUG` and `RUST_BACKTRACE` is enabled, the backtrace is also logged.
These are configurable with environmental variables:
```
>> RUST_BACKTRACE=1 RUST_LOG=actix_web=debug cargo run
```
The `Error` type uses the cause's error backtrace if available. If the
underlying failure does not provide a backtrace, a new backtrace is constructed
pointing to the point where the conversion occurred (rather than the origin of
the error).
# Recommended practices in error handling
It might be useful to think about dividing the errors an application produces
into two broad groups: those which are intended to be be user-facing, and those
which are not.
An example of the former is that I might use failure to specify a `UserError`
enum which encapsulates a `ValidationError` to return whenever a user sends bad
input:
```rust
#[macro_use] extern crate failure;
use actix_web::{HttpResponse, http, error};
#[derive(Fail, Debug)]
enum UserError {
#[fail(display="Validation error on field: {}", field)]
ValidationError {
field: String,
}
}
impl error::ResponseError for UserError {
fn error_response(&self) -> HttpResponse {
match *self {
UserError::ValidationError { .. } => HttpResponse::new(
http::StatusCode::BAD_REQUEST),
}
}
}
```
This will behave exactly as intended because the error message defined with
`display` is written with the explicit intent to be read by a user.
However, sending back an error's message isn't desirable for all errors --
there are many failures that occur in a server environment where we'd probably
want the specifics to be hidden from the user. For example, if a database goes
down and client libraries start producing connect timeout errors, or if an HTML
template was improperly formatted and errors when rendered. In these cases, it
might be preferable to map the errors to a generic error suitable for user
consumption.
Here's an example that maps an internal error to a user-facing `InternalError`
with a custom message:
```rust
#[macro_use] extern crate failure;
use actix_web::{App, HttpRequest, HttpResponse, http, error, fs};
#[derive(Fail, Debug)]
enum UserError {
#[fail(display="An internal error occurred. Please try again later.")]
InternalError,
}
impl error::ResponseError for UserError {
fn error_response(&self) -> HttpResponse {
match *self {
UserError::InternalError => HttpResponse::new(
http::StatusCode::INTERNAL_SERVER_ERROR),
}
}
}
fn index(_req: HttpRequest) -> Result<&'static str, UserError> {
fs::NamedFile::open("static/index.html").map_err(|_e| UserError::InternalError)?;
Ok("success!")
}
```
By dividing errors into those which are user facing and those which are not, we
can ensure that we don't accidentally expose users to errors thrown by
application internals which they weren't meant to see.
[actixerror]: ../../actix-web/actix_web/error/struct.Error.html
[errorhelpers]: ../../actix-web/actix_web/error/index.html#functions
[failure]: https://github.com/rust-lang-nursery/failure
[responseerror]: ../../actix-web/actix_web/error/trait.ResponseError.html
[responseerrorimpls]: ../../actix-web/actix_web/error/trait.ResponseError.html#foreign-impls
[stderror]: https://doc.rust-lang.org/std/error/trait.Error.html

View File

@ -1,284 +0,0 @@
---
title: Extractors
menu: docs_basics
weight: 170
---
# Type-safe information extraction
Actix provides facility for type-safe request information extraction. By default,
actix provides several extractor implementations.
# Accessing Extractors
How you access an Extractor depends on whether you are using a handler function
or a custom Handler type.
## Within Handler Functions
An Extractor can be passed to a handler function as a function parameter
*or* accessed within the function by calling the ExtractorType::<...>::extract(req)
function.
```rust
// Option 1: passed as a parameter to a handler function
fn index((params, info): (Path<(String, String,)>, Json<MyInfo>)) -> HttpResponse {
...
}
// Option 2: accessed by calling extract() on the Extractor
use actix_web::FromRequest;
fn index(req: HttpRequest) -> HttpResponse {
let params = Path::<(String, String)>::extract(&req);
let info = Json::<MyInfo>::extract(&req);
...
}
```
## Within Custom Handler Types
Like a handler function, a custom Handler type can *access* an Extractor by
calling the ExtractorType::<...>::extract(&req) function. An Extractor
*cannot* be passed as a parameter to a custom Handler type because a custom
Handler type must follow the ``handle`` function signature specified by the
Handler trait it implements.
```rust
struct MyHandler(String);
impl<S> Handler<S> for MyHandler {
type Result = HttpResponse;
/// Handle request
fn handle(&mut self, req: HttpRequest<S>) -> Self::Result {
let params = Path::<(String, String)>::extract(&req);
let info = Json::<MyInfo>::extract(&req);
...
HttpResponse::Ok().into()
}
}
```
# Path
[*Path*](../../actix-web/actix_web/struct.Path.html) provides information that can
be extracted from the Request's path. You can deserialize any variable
segment from the path.
For instance, for resource that registered for the `/users/{userid}/{friend}` path
two segments could be deserialized, `userid` and `friend`. These segments
could be extracted into a `tuple`, i.e. `Path<(u32, String)>` or any structure
that implements the `Deserialize` trait from the *serde* crate.
```rust
use actix_web::{App, Path, Result, http};
/// extract path info from "/users/{userid}/{friend}" url
/// {userid} - - deserializes to a u32
/// {friend} - deserializes to a String
fn index(info: Path<(u32, String)>) -> Result<String> {
Ok(format!("Welcome {}! {}", info.1, info.0))
}
fn main() {
let app = App::new().resource(
"/users/{userid}/{friend}", // <- define path parameters
|r| r.method(http::Method::GET).with(index)); // <- use `with` extractor
}
```
Remember! A handler function that uses extractors has to be registered using the
[*Route::with()*](../../actix-web/actix_web/dev/struct.Route.html#method.with) method.
It is also possible to extract path information to a specific type that
implements the `Deserialize` trait from *serde*. Here is an equivalent example that uses *serde*
instead of a *tuple* type.
```rust
#[macro_use] extern crate serde_derive;
use actix_web::{App, Path, Result, http};
#[derive(Deserialize)]
struct Info {
userid: u32,
friend: String,
}
/// extract path info using serde
fn index(info: Path<Info>) -> Result<String> {
Ok(format!("Welcome {}!", info.friend))
}
fn main() {
let app = App::new().resource(
"/users/{userid}/{friend}", // <- define path parameters
|r| r.method(http::Method::GET).with(index)); // <- use `with` extractor
}
```
# Query
Same can be done with the request's query.
The [*Query*](../../actix-web/actix_web/struct.Query.html)
type provides extraction functionality. Underneath it uses *serde_urlencoded* crate.
```rust
#[macro_use] extern crate serde_derive;
use actix_web::{App, Query, http};
#[derive(Deserialize)]
struct Info {
username: String,
}
// this handler get called only if the request's query contains `username` field
fn index(info: Query<Info>) -> String {
format!("Welcome {}!", info.username)
}
fn main() {
let app = App::new().resource(
"/index.html",
|r| r.method(http::Method::GET).with(index)); // <- use `with` extractor
}
```
# Json
[*Json*](../../actix-web/actix_web/struct.Json.html) allows to deserialize
a request body into a struct. To extract typed information from a request's body,
the type `T` must implement the `Deserialize` trait from *serde*.
```rust
#[macro_use] extern crate serde_derive;
use actix_web::{App, Json, Result, http};
#[derive(Deserialize)]
struct Info {
username: String,
}
/// deserialize `Info` from request's body
fn index(info: Json<Info>) -> Result<String> {
Ok(format!("Welcome {}!", info.username))
}
fn main() {
let app = App::new().resource(
"/index.html",
|r| r.method(http::Method::POST).with(index)); // <- use `with` extractor
}
```
Some extractors provide a way to configure the extraction process. Json extractor
[*JsonConfig*](../../actix-web/actix_web/dev/struct.JsonConfig.html) type for configuration.
When you register a handler using `Route::with()`, it returns a configuration instance. In case of
a *Json* extractor it returns a *JsonConfig*. You can configure the maximum size of the json
payload as well as a custom error handler function.
The following example limits the size of the payload to 4kb and uses a custom error hander.
```rust
#[macro_use] extern crate serde_derive;
use actix_web::{App, Json, HttpResponse, Result, http, error};
#[derive(Deserialize)]
struct Info {
username: String,
}
/// deserialize `Info` from request's body, max payload size is 4kb
fn index(info: Json<Info>) -> Result<String> {
Ok(format!("Welcome {}!", info.username))
}
fn main() {
let app = App::new().resource(
"/index.html", |r| {
r.method(http::Method::POST)
.with(index)
.limit(4096) // <- change json extractor configuration
.error_handler(|err, req| { // <- create custom error response
error::InternalError::from_response(
err, HttpResponse::Conflict().finish()).into()
});
});
}
```
# Form
At the moment only url-encoded forms are supported. The url-encoded body
could be extracted to a specific type. This type must implement
the `Deserialize` trait from the *serde* crate.
[*FormConfig*](../../actix-web/actix_web/dev/struct.FormConfig.html) allows
configuring the extraction process.
```rust
#[macro_use] extern crate serde_derive;
use actix_web::{App, Form, Result};
#[derive(Deserialize)]
struct FormData {
username: String,
}
/// extract form data using serde
/// this handler gets called only if the content type is *x-www-form-urlencoded*
/// and the content of the request could be deserialized to a `FormData` struct
fn index(form: Form<FormData>) -> Result<String> {
Ok(format!("Welcome {}!", form.username))
}
# fn main() {}
```
# Multiple extractors
Actix provides extractor implementations for tuples (up to 10 elements)
whose elements implement `FromRequest`.
For example we can use a path extractor and a query extractor at the same time.
```rust
#[macro_use] extern crate serde_derive;
use actix_web::{App, Query, Path, http};
#[derive(Deserialize)]
struct Info {
username: String,
}
fn index((path, query): (Path<(u32, String)>, Query<Info>)) -> String {
format!("Welcome {}!", query.username)
}
fn main() {
let app = App::new().resource(
"/users/{userid}/{friend}", // <- define path parameters
|r| r.method(http::Method::GET).with(index)); // <- use `with` extractor
}
```
# Other
Actix also provides several other extractors:
* [*State*](../../actix-web/actix_web/struct.State.html) - If you need
access to an application state. This is similar to a `HttpRequest::state()`.
* *HttpRequest* - *HttpRequest* itself is an extractor which returns self,
in case you need access to the request.
* *String* - You can convert a request's payload to a *String*.
[*Example*](../../actix-web/actix_web/trait.FromRequest.html#example-1)
is available in doc strings.
* *bytes::Bytes* - You can convert a request's payload into *Bytes*.
[*Example*](../../actix-web/actix_web/trait.FromRequest.html#example)
is available in doc strings.

View File

@ -1,40 +0,0 @@
---
title: 开始
menu: docs_basics
weight: 130
---
# 开始
我们来编写第一个actix web应用程序
## Hello, world!
首先创建一个新的基于二进制的Cargo项目并进入新目录
```bash
cargo new hello-world
cd hello-world
```
现在确保actix-web的Cargo.toml 包含以下项目依赖关系:
```ini
[dependencies]
actix-web = "{{< actix-version "actix-web" >}}"
```
为了实现一个Web服务器我们首先需要创建一个请求处理程序。请求处理函数接受一个HttpRequest实例作为其唯一参数并返回一个可转换为HttpResponse的类型
文件名: `src/main.rs`
{{< include-example example="getting-started" section="setup" >}}
接下来创建一个Application实例并将请求处理程序与应用程序的resource一起注册在特定HTTP方法和路径然后应用程序实例可以用于HttpServer来侦听将传入的连接。服务器接受一个应该返回一个HttpHandler实例的函数 。简单来说server::new可以使用了它是HttpServer::new的简写
{{< include-example example="getting-started" section="main" >}}
仅此而已现在编译并运行该程序cargo run。去http://localhost:8088 看结果。
如果你想要在开发过程中重新编译后自动重新加载服务器。请查看[自动重新加载模式](../autoreload/)。

View File

@ -1,292 +0,0 @@
---
title: Handlers
menu: docs_basics
weight: 160
---
# Request Handlers
A request handler can be any object that implements
[*Handler*](../../actix-web/actix_web/dev/trait.Handler.html) trait.
Request handling happens in two stages. First the handler object is called,
returning any object that implements the
[*Responder*](../../actix-web/actix_web/trait.Responder.html#foreign-impls) trait.
Then, `respond_to()` is called on the returned object, converting itself to a `AsyncResult` or `Error`.
By default actix provides `Responder` implementations for some standard types,
such as `&'static str`, `String`, etc.
> For a complete list of implementations, check
> [*Responder documentation*](../../actix-web/actix_web/trait.Responder.html#foreign-impls).
Examples of valid handlers:
```rust
fn index(req: HttpRequest) -> &'static str {
"Hello world!"
}
```
```rust
fn index(req: HttpRequest) -> String {
"Hello world!".to_owned()
}
```
You can also change the signature to return `impl Responder` which works well if more
complex types are involved.
```rust
fn index(req: HttpRequest) -> impl Responder {
Bytes::from_static("Hello world!")
}
```
```rust,ignore
fn index(req: HttpRequest) -> Box<Future<Item=HttpResponse, Error=Error>> {
...
}
```
*Handler* trait is generic over *S*, which defines the application state's type.
Application state is accessible from the handler with the `HttpRequest::state()` method;
however, state is accessible as a read-only reference. If you need mutable access to state,
it must be implemented.
> **Note**: Alternatively, the handler can mutably access its own state because the `handle` method takes
> mutable reference to *self*. **Beware**, actix creates multiple copies
> of the application state and the handlers, unique for each thread. If you run your
> application in several threads, actix will create the same amount as number of threads
> of application state objects and handler objects.
Here is an example of a handler that stores the number of processed requests:
```rust
use actix_web::{App, HttpRequest, HttpResponse, dev::Handler};
struct MyHandler(usize);
impl<S> Handler<S> for MyHandler {
type Result = HttpResponse;
/// Handle request
fn handle(&mut self, req: HttpRequest<S>) -> Self::Result {
self.0 += 1;
HttpResponse::Ok().into()
}
}
```
Although this handler will work, `self.0` will be different depending on the number of threads and
number of requests processed per thread. A proper implementation would use `Arc` and `AtomicUsize`.
```rust
use actix_web::{server, App, HttpRequest, HttpResponse, dev::Handler};
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
struct MyHandler(Arc<AtomicUsize>);
impl<S> Handler<S> for MyHandler {
type Result = HttpResponse;
/// Handle request
fn handle(&mut self, req: HttpRequest<S>) -> Self::Result {
self.0.fetch_add(1, Ordering::Relaxed);
HttpResponse::Ok().into()
}
}
fn main() {
let sys = actix::System::new("example");
let inc = Arc::new(AtomicUsize::new(0));
server::new(
move || {
let cloned = inc.clone();
App::new()
.resource("/", move |r| r.h(MyHandler(cloned)))
})
.bind("127.0.0.1:8088").unwrap()
.start();
println!("Started http server: 127.0.0.1:8088");
let _ = sys.run();
}
```
> Be careful with synchronization primitives like `Mutex` or `RwLock`. The `actix-web` framework
> handles requests asynchronously. By blocking thread execution, all concurrent
> request handling processes would block. If you need to share or update some state
> from multiple threads, consider using the [actix](https://actix.github.io/actix/actix/) actor system.
## Response with custom type
To return a custom type directly from a handler function, the type needs to implement the `Responder` trait.
Let's create a response for a custom type that serializes to an `application/json` response:
```rust
# extern crate actix;
# extern crate actix_web;
extern crate serde;
extern crate serde_json;
#[macro_use] extern crate serde_derive;
use actix_web::{server, App, HttpRequest, HttpResponse, Error, Responder, http};
#[derive(Serialize)]
struct MyObj {
name: &'static str,
}
/// Responder
impl Responder for MyObj {
type Item = HttpResponse;
type Error = Error;
fn respond_to<S>(self, req: &HttpRequest<S>) -> Result<HttpResponse, Error> {
let body = serde_json::to_string(&self)?;
// Create response and set content type
Ok(HttpResponse::Ok()
.content_type("application/json")
.body(body))
}
}
fn index(req: HttpRequest) -> impl Responder {
MyObj { name: "user" }
}
fn main() {
let sys = actix::System::new("example");
server::new(
|| App::new()
.resource("/", |r| r.method(http::Method::GET).f(index)))
.bind("127.0.0.1:8088").unwrap()
.start();
println!("Started http server: 127.0.0.1:8088");
let _ = sys.run();
}
```
## Async handlers
There are two different types of async handlers. Response objects can be generated asynchronously
or more precisely, any type that implements the [*Responder*](../../actix-web/actix_web/trait.Responder.html) trait.
In this case, the handler must return a `Future` object that resolves to the *Responder* type, i.e:
```rust
use actix_web::*;
use bytes::Bytes;
use futures::stream::once;
use futures::future::{Future, result};
fn index(req: HttpRequest) -> Box<Future<Item=HttpResponse, Error=Error>> {
result(Ok(HttpResponse::Ok()
.content_type("text/html")
.body(format!("Hello!"))))
.responder()
}
fn index2(req: HttpRequest) -> Box<Future<Item=&'static str, Error=Error>> {
result(Ok("Welcome!"))
.responder()
}
fn main() {
App::new()
.resource("/async", |r| r.route().a(index))
.resource("/", |r| r.route().a(index2))
.finish();
}
```
Or the response body can be generated asynchronously. In this case, body
must implement the stream trait `Stream<Item=Bytes, Error=Error>`, i.e:
```rust
use actix_web::*;
use bytes::Bytes;
use futures::stream::once;
fn index(req: HttpRequest) -> HttpResponse {
let body = once(Ok(Bytes::from_static(b"test")));
HttpResponse::Ok()
.content_type("application/json")
.body(Body::Streaming(Box::new(body)))
}
fn main() {
App::new()
.resource("/async", |r| r.f(index))
.finish();
}
```
Both methods can be combined. (i.e Async response with streaming body)
It is possible to return a `Result` where the `Result::Item` type can be `Future`.
In this example, the `index` handler can return an error immediately or return a
future that resolves to a `HttpResponse`.
```rust
use actix_web::*;
use bytes::Bytes;
use futures::stream::once;
use futures::future::{Future, result};
fn index(req: HttpRequest) -> Result<Box<Future<Item=HttpResponse, Error=Error>>, Error> {
if is_error() {
Err(error::ErrorBadRequest("bad request"))
} else {
Ok(Box::new(
result(Ok(HttpResponse::Ok()
.content_type("text/html")
.body(format!("Hello!"))))))
}
}
```
## Different return types (Either)
Sometimes, you need to return different types of responses. For example,
you can error check and return errors, return async responses, or any result that requires two different types.
For this case, the [*Either*](../../actix-web/actix_web/enum.Either.html) type can be used.
`Either` allows combining two different responder types into a single type.
```rust
use futures::future::{Future, result};
use actix_web::{Either, Error, HttpResponse};
type RegisterResult = Either<HttpResponse, Box<Future<Item=HttpResponse, Error=Error>>>;
fn index(req: HttpRequest) -> impl Responder {
if is_a_variant() { // <- choose variant A
Either::A(
HttpResponse::BadRequest().body("Bad data"))
} else {
Either::B( // <- variant B
result(Ok(HttpResponse::Ok()
.content_type("text/html")
.body(format!("Hello!")))).responder())
}
}
```
## Tokio core handle
Any `actix-web` handler runs within a properly configured
[actix system](https://actix.github.io/actix/actix/struct.System.html)
and [arbiter](https://actix.github.io/actix/actix/struct.Arbiter.html).
You can always get access to the tokio handle via the
[Arbiter::handle()](https://actix.github.io/actix/actix/struct.Arbiter.html#method.handle)
method.

View File

@ -1,45 +0,0 @@
---
title: HTTP/2.0
menu: docs_proto
weight: 250
---
如果可能`actix-web`自动升级到*HTTP/2.0*的连接。
# 协议
*HTTP/2.0* protocol over tls without prior knowledge requires [tls alpn](https://tools.ietf.org/html/rfc7301).
> 目前,只有`rust-openssl`支持
`alpn`协议需要启用该功能。启用后HttpServer提供 serve_tls方法。
[serve_tls](https://actix.rs/actix-web/actix_web/server/struct.HttpServer.html#method.serve_tls) method.
```toml
[dependencies]
actix-web = { version = "{{< actix-version "actix-web" >}}", features = ["alpn"] }
openssl = { version = "0.10", features = ["v110"] }
```
```rust
use std::fs::File;
use actix_web::*;
use openssl::ssl::{SslMethod, SslAcceptor, SslFiletype};
fn main() {
// load ssl keys
let mut builder = SslAcceptor::mozilla_intermediate(SslMethod::tls()).unwrap();
builder.set_private_key_file("key.pem", SslFiletype::PEM).unwrap();
builder.set_certificate_chain_file("cert.pem").unwrap();
HttpServer::new(
|| App::new()
.resource("/index.html", |r| r.f(index)))
.bind("127.0.0.1:8080").unwrap();
.serve_ssl(builder).unwrap();
}
```
不支持升级到[rfc section 3.2](https://http2.github.io/http2-spec/#rfc.section.3.2) 节中描述的HTTP/2.0模式 。明文连接和tls连接都支持*HTTP/2* with prior knowledge启动,[rfc section 3.4](https://http2.github.io/http2-spec/#rfc.section.3.4)
查看具体示例[examples/tls](https://github.com/actix/examples/tree/master/tls).

View File

@ -1,250 +0,0 @@
---
title: Middlewares
menu: docs_advanced
weight: 220
---
# Middleware
Actix's middleware system allows us to add additional behavior to request/response processing.
Middleware can hook into an incoming request process, enabling us to modify requests
as well as halt request processing to return a response early.
Middleware can also hook into response processing.
Typically, middleware is involved in the following actions:
* Pre-process the Request
* Post-process a Response
* Modify application state
* Access external services (redis, logging, sessions)
Middleware is registered for each application and executed in same order as
registration. In general, a *middleware* is a type that implements the
[*Middleware trait*](../../actix-web/actix_web/middleware/trait.Middleware.html).
Each method in this trait has a default implementation. Each method can return
a result immediately or a *future* object.
The following demonstrates using middleware to add request and response headers:
```rust
use http::{header, HttpTryFrom};
use actix_web::{App, HttpRequest, HttpResponse, Result};
use actix_web::middleware::{Middleware, Started, Response};
struct Headers; // <- Our middleware
/// Middleware implementation, middlewares are generic over application state,
/// so you can access state with `HttpRequest::state()` method.
impl<S> Middleware<S> for Headers {
/// Method is called when request is ready. It may return
/// future, which should resolve before next middleware get called.
fn start(&self, req: &mut HttpRequest<S>) -> Result<Started> {
req.headers_mut().insert(
header::CONTENT_TYPE, header::HeaderValue::from_static("text/plain"));
Ok(Started::Done)
}
/// Method is called when handler returns response,
/// but before sending http message to peer.
fn response(&self, req: &mut HttpRequest<S>, mut resp: HttpResponse)
-> Result<Response>
{
resp.headers_mut().insert(
header::HeaderName::try_from("X-VERSION").unwrap(),
header::HeaderValue::from_static("0.2"));
Ok(Response::Done(resp))
}
}
fn main() {
App::new()
// Register middleware, this method can be called multiple times
.middleware(Headers)
.resource("/", |r| r.f(|_| HttpResponse::Ok()));
}
```
> Actix provides several useful middlewares, such as *logging*, *user sessions*, etc.
# Logging
Logging is implemented as a middleware.
It is common to register a logging middleware as the first middleware for the application.
Logging middleware must be registered for each application.
The `Logger` middleware uses the standard log crate to log information. You should enable logger
for *actix_web* package to see access log ([env_logger](https://docs.rs/env_logger/*/env_logger/)
or similar).
## Usage
Create `Logger` middleware with the specified `format`.
Default `Logger` can be created with `default` method, it uses the default format:
```ignore
%a %t "%r" %s %b "%{Referer}i" "%{User-Agent}i" %T
```
```rust
extern crate env_logger;
use actix_web::App;
use actix_web::middleware::Logger;
fn main() {
std::env::set_var("RUST_LOG", "actix_web=info");
env_logger::init();
App::new()
.middleware(Logger::default())
.middleware(Logger::new("%a %{User-Agent}i"))
.finish();
}
```
The following is an example of the default logging format:
```
INFO:actix_web::middleware::logger: 127.0.0.1:59934 [02/Dec/2017:00:21:43 -0800] "GET / HTTP/1.1" 302 0 "-" "curl/7.54.0" 0.000397
INFO:actix_web::middleware::logger: 127.0.0.1:59947 [02/Dec/2017:00:22:40 -0800] "GET /index.html HTTP/1.1" 200 0 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:57.0) Gecko/20100101 Firefox/57.0" 0.000646
```
## Format
`%%` The percent sign
`%a` Remote IP-address (IP-address of proxy if using reverse proxy)
`%t` Time when the request was started to process
`%P` The process ID of the child that serviced the request
`%r` First line of request
`%s` Response status code
`%b` Size of response in bytes, including HTTP headers
`%T` Time taken to serve the request, in seconds with floating fraction in .06f format
`%D` Time taken to serve the request, in milliseconds
`%{FOO}i` request.headers['FOO']
`%{FOO}o` response.headers['FOO']
`%{FOO}e` os.environ['FOO']
## Default headers
To set default response headers, the `DefaultHeaders` middleware can be used. The
*DefaultHeaders* middleware does not set the header if response headers already contain
a specified header.
```rust
use actix_web::{http, middleware, App, HttpResponse};
fn main() {
let app = App::new()
.middleware(
middleware::DefaultHeaders::new()
.header("X-Version", "0.2"))
.resource("/test", |r| {
r.method(http::Method::GET).f(|req| HttpResponse::Ok());
r.method(http::Method::HEAD).f(|req| HttpResponse::MethodNotAllowed());
})
.finish();
}
```
## User sessions
Actix provides a general solution for session management. The
[**SessionStorage**](../../actix-web/actix_web/middleware/session/struct.SessionStorage.html) middleware can be
used with different backend types to store session data in different backends.
> By default, only cookie session backend is implemented. Other backend implementations
> can be added.
[**CookieSessionBackend**](../../actix-web/actix_web/middleware/session/struct.CookieSessionBackend.html)
uses cookies as session storage. `CookieSessionBackend` creates sessions which
are limited to storing fewer than 4000 bytes of data, as the payload must fit into a
single cookie. An internal server error is generated if a session contains more than 4000 bytes.
A cookie may have a security policy of *signed* or *private*. Each has a respective `CookieSessionBackend` constructor.
A *signed* cookie may be viewed but not modified by the client. A *private* cookie may neither be viewed nor modified by the client.
The constructors take a key as an argument. This is the private key for cookie session - when this value is changed, all session data is lost.
In general, you create a
`SessionStorage` middleware and initialize it with specific backend implementation,
such as a `CookieSessionBackend`. To access session data,
[*HttpRequest::session()*](../../actix-web/actix_web/middleware/session/trait.RequestSession.html#tymethod.session)
must be used. This method returns a
[*Session*](../../actix-web/actix_web/middleware/session/struct.Session.html) object, which allows us to get or set
session data.
```rust
use actix_web::{server, App, HttpRequest, Result};
use actix_web::middleware::session::{RequestSession, SessionStorage, CookieSessionBackend};
fn index(mut req: HttpRequest) -> Result<&'static str> {
// access session data
if let Some(count) = req.session().get::<i32>("counter")? {
println!("SESSION value: {}", count);
req.session().set("counter", count+1)?;
} else {
req.session().set("counter", 1)?;
}
Ok("Welcome!")
}
fn main() {
let sys = actix::System::new("basic-example");
server::new(
|| App::new().middleware(
SessionStorage::new(
CookieSessionBackend::signed(&[0; 32])
.secure(false)
)))
.bind("127.0.0.1:59880").unwrap()
.start();
let _ = sys.run();
}
```
# Error handlers
`ErrorHandlers` middleware allows us to provide custom handlers for responses.
You can use the `ErrorHandlers::handler()` method to register a custom error handler
for a specific status code. You can modify an existing response or create a completly new
one. The error handler can return a response immediately or return a future that resolves
into a response.
```rust
use actix_web::{
App, HttpRequest, HttpResponse, Result,
http, middleware::Response, middleware::ErrorHandlers};
fn render_500<S>(_: &mut HttpRequest<S>, resp: HttpResponse) -> Result<Response> {
let mut builder = resp.into_builder();
builder.header(http::header::CONTENT_TYPE, "application/json");
Ok(Response::Done(builder.into()))
}
fn main() {
let app = App::new()
.middleware(
ErrorHandlers::new()
.handler(http::StatusCode::INTERNAL_SERVER_ERROR, render_500))
.resource("/test", |r| {
r.method(http::Method::GET).f(|_| HttpResponse::Ok());
r.method(http::Method::HEAD).f(|_| HttpResponse::MethodNotAllowed());
})
.finish();
}
```

View File

@ -1,207 +0,0 @@
---
title: Requests
menu: docs_advanced
weight: 200
---
# Content Encoding
Actix automatically *decompresses* payloads. The following codecs are supported:
* Brotli
* Gzip
* Deflate
* Identity
If request headers contain a `Content-Encoding` header, the request payload is decompressed
according to the header value. Multiple codecs are not supported,
i.e: `Content-Encoding: br, gzip`.
# JSON Request
There are several options for json body deserialization.
The first option is to use *Json* extractor. First, you define a handler function
that accepts `Json<T>` as a parameter, then, you use the `.with()` method for registering
this handler. It is also possible to accept arbitrary valid json object by
using `serde_json::Value` as a type `T`.
```rust
#[macro_use] extern crate serde_derive;
use actix_web::{App, Json, Result, http};
#[derive(Deserialize)]
struct Info {
username: String,
}
/// extract `Info` using serde
fn index(info: Json<Info>) -> Result<String> {
Ok(format!("Welcome {}!", info.username))
}
fn main() {
let app = App::new().resource(
"/index.html",
|r| r.method(http::Method::POST).with(index)); // <- use `with` extractor
}
```
Another option is to use *HttpRequest::json()*. This method returns a
[*JsonBody*](../../actix-web/actix_web/dev/struct.JsonBody.html) object which resolves into
the deserialized value.
```rust
#[derive(Debug, Serialize, Deserialize)]
struct MyObj {
name: String,
number: i32,
}
fn index(mut req: HttpRequest) -> Box<Future<Item=HttpResponse, Error=Error>> {
req.json().from_err()
.and_then(|val: MyObj| {
println!("model: {:?}", val);
Ok(HttpResponse::Ok().json(val)) // <- send response
})
.responder()
}
```
You may also manually load the payload into memory and then deserialize it.
In the following example, we will deserialize a *MyObj* struct. We need to load the request
body first and then deserialize the json into an object.
```rust
extern crate serde_json;
use futures::{Future, Stream};
#[derive(Serialize, Deserialize)]
struct MyObj {name: String, number: i32}
fn index(req: HttpRequest) -> Box<Future<Item=HttpResponse, Error=Error>> {
// `concat2` will asynchronously read each chunk of the request body and
// return a single, concatenated, chunk
req.concat2()
// `Future::from_err` acts like `?` in that it coerces the error type from
// the future into the final error type
.from_err()
// `Future::and_then` can be used to merge an asynchronous workflow with a
// synchronous workflow
.and_then(|body| {
let obj = serde_json::from_slice::<MyObj>(&body)?;
Ok(HttpResponse::Ok().json(obj))
})
.responder()
}
```
> A complete example for both options is available in
> [examples directory](https://github.com/actix/examples/tree/master/json/).
# Chunked transfer encoding
Actix automatically decodes *chunked* encoding. `HttpRequest::payload()` already contains
the decoded byte stream. If the request payload is compressed with one of the supported
compression codecs (br, gzip, deflate), then the byte stream is decompressed.
# Multipart body
Actix provides multipart stream support.
[*Multipart*](../../actix-web/actix_web/multipart/struct.Multipart.html) is implemented as
a stream of multipart items. Each item can be a
[*Field*](../../actix-web/actix_web/multipart/struct.Field.html) or a nested
*Multipart* stream.`HttpResponse::multipart()` returns the *Multipart* stream
for the current request.
The following demonstrates multipart stream handling for a simple form:
```rust
use actix_web::*;
fn index(req: HttpRequest) -> Box<Future<...>> {
// get multipart and iterate over multipart items
req.multipart()
.and_then(|item| {
match item {
multipart::MultipartItem::Field(field) => {
println!("==== FIELD ==== {:?} {:?}",
field.headers(),
field.content_type());
Either::A(
field.map(|chunk| {
println!("-- CHUNK: \n{}",
std::str::from_utf8(&chunk).unwrap());})
.fold((), |_, _| result(Ok(()))))
},
multipart::MultipartItem::Nested(mp) => {
Either::B(result(Ok(())))
}
}
})
}
```
> A full example is available in the
> [examples directory](https://github.com/actix/examples/tree/master/multipart/).
# Urlencoded body
Actix provides support for *application/x-www-form-urlencoded* encoded bodies.
`HttpResponse::urlencoded()` returns a
[*UrlEncoded*](../../actix-web/actix_web/dev/struct.UrlEncoded.html) future, which resolves
to the deserialized instance. The type of the instance must implement the
`Deserialize` trait from *serde*.
The *UrlEncoded* future can resolve into an error in several cases:
* content type is not `application/x-www-form-urlencoded`
* transfer encoding is `chunked`.
* content-length is greater than 256k
* payload terminates with error.
```rust
#[macro_use] extern crate serde_derive;
use actix_web::*;
use futures::future::{Future, ok};
#[derive(Deserialize)]
struct FormData {
username: String,
}
fn index(mut req: HttpRequest) -> Box<Future<Item=HttpResponse, Error=Error>> {
req.urlencoded::<FormData>() // <- get UrlEncoded future
.from_err()
.and_then(|data| { // <- deserialized instance
println!("USERNAME: {:?}", data.username);
ok(HttpResponse::Ok().into())
})
.responder()
}
# fn main() {}
```
# Streaming request
*HttpRequest* is a stream of `Bytes` objects. It can be used to read the request
body payload.
In the following example, we read and print the request payload chunk by chunk:
```rust
use actix_web::*;
use futures::{Future, Stream};
fn index(mut req: HttpRequest) -> Box<Future<Item=HttpResponse, Error=Error>> {
req.from_err()
.fold((), |_, chunk| {
println!("Chunk: {:?}", chunk);
result::<_, error::PayloadError>(Ok(()))
})
.map(|_| HttpResponse::Ok().finish())
.responder()
}
```

View File

@ -1,140 +0,0 @@
---
title: Responses
menu: docs_advanced
weight: 210
---
# Response
A builder-like pattern is used to construct an instance of `HttpResponse`.
`HttpResponse` provides several methods that return a `HttpResponseBuilder` instance,
which implements various convenience methods for building responses.
> Check the [documentation](../../actix-web/actix_web/dev/struct.HttpResponseBuilder.html)
> for type descriptions.
The methods `.body`, `.finish`, and `.json` finalize response creation and
return a constructed *HttpResponse* instance. If this methods is called on the same
builder instance multiple times, the builder will panic.
```rust
use actix_web::{HttpRequest, HttpResponse, http::ContentEncoding};
fn index(req: HttpRequest) -> HttpResponse {
HttpResponse::Ok()
.content_encoding(ContentEncoding::Br)
.content_type("plain/text")
.header("X-Hdr", "sample")
.body("data")
}
```
# Content encoding
Actix automatically *compresses* payloads. The following codecs are supported:
* Brotli
* Gzip
* Deflate
* Identity
Response payload is compressed based on the *content_encoding* parameter.
By default, `ContentEncoding::Auto` is used. If `ContentEncoding::Auto` is selected,
then the compression depends on the request's `Accept-Encoding` header.
> `ContentEncoding::Identity` can be used to disable compression.
> If another content encoding is selected, the compression is enforced for that codec.
For example, to enable `brotli` use `ContentEncoding::Br`:
```rust
use actix_web::{HttpRequest, HttpResponse, http::ContentEncoding};
fn index(req: HttpRequest) -> HttpResponse {
HttpResponse::Ok()
.content_encoding(ContentEncoding::Br)
.body("data")
}
```
In this case we explicitly disable content compression
by setting content encoding to a `Identity` value:
```rust
use actix_web::{HttpRequest, HttpResponse, http::ContentEncoding};
fn index(req: HttpRequest) -> HttpResponse {
HttpResponse::Ok()
// v- disable compression
.content_encoding(ContentEncoding::Identity)
.body("data")
}
```
Also it is possible to set default content encoding on application level, by
default `ContentEncoding::Auto` is used, which implies automatic content compression
negotiation.
```rust
use actix_web::{App, HttpRequest, HttpResponse, http::ContentEncoding};
fn index(req: HttpRequest) -> HttpResponse {
HttpResponse::Ok()
.body("data")
}
fn main() {
let app = App::new()
// v- disable compression for all routes
.default_encoding(ContentEncoding::Identity)
.resource("/index.html", |r| r.with(index));
}
```
# JSON Response
The `Json` type allows to respond with well-formed JSON data: simply return a value of
type Json<T> where `T` is the type of a structure to serialize into *JSON*.
The type `T` must implement the `Serialize` trait from *serde*.
```rust
# extern crate actix_web;
#[macro_use] extern crate serde_derive;
use actix_web::{App, HttpRequest, Json, Result, http::Method};
#[derive(Serialize)]
struct MyObj {
name: String,
}
fn index(req: HttpRequest) -> Result<Json<MyObj>> {
Ok(Json(MyObj{name: req.match_info().query("name")?}))
}
fn main() {
App::new()
.resource(r"/a/{name}", |r| r.method(Method::GET).f(index))
.finish();
}
```
# Chunked transfer encoding
Chunked encoding on a response can be enabled with `HttpResponseBuilder::chunked()`.
This takes effect only for `Body::Streaming(BodyStream)` or `Body::StreamingContext` bodies.
If the response payload compression is enabled and a streaming body is used, chunked encoding
is enabled automatically.
> Enabling chunked encoding for *HTTP/2.0* responses is forbidden.
```rust
use actix_web::*;
use bytes::Bytes;
use futures::stream::once;
fn index(req: HttpRequest) -> HttpResponse {
HttpResponse::Ok()
.chunked()
.body(Body::Streaming(Box::new(once(Ok(Bytes::from_static(b"data"))))))
}
```

View File

@ -1,61 +0,0 @@
---
title: Sentry
menu: docs_patterns
weight: 1020
---
# Sentry崩溃报告
[Sentry](https://sentry.io/)是一个崩溃报告系统它支持基于actix错误报告的failure crate。使用Sentry中间件可以自动将服务器错误报告给Sentry。
# Sentry中间件
该中间件捕获服务器错误范围500-599中的任何错误并通过其堆栈跟踪将附加的错误发送给哨兵。
要使用中间件需要初始化和配置Sentry并且需要添加sentry-actix中间件。此外注册panic处理程序以通知困难panic也是有意义的。
```rust
extern crate sentry;
extern crate sentry_actix;
use sentry_actix::SentryMiddleware;
use std::env;
fn main() {
sentry::init("SENTRY_DSN_GOES_HERE");
env::set_var("RUST_BACKTRACE", "1");
sentry::integrations::panic::register_panic_handler();
let mut app = App::with_state(state)
.middleware(SentryMiddleware::new())
// ...
}
```
# Reusing the Hub
如果使用这种集成默认的sentry hubHub::current()通常是错误的。要获得特定的请求您需要使用ActixWebHubExt trait
```rust
use sentry::{Hub, Level};
use sentry_actix::ActixWebHubExt;
let hub = Hub::from_request(req);
hub.capture_message("Something is not well", Level::Warning);
```
The hub can also be made current for the duration of a call. Then Hub::current() works correctly until the end of the run block.
```rust
use sentry::{Hub, Level};
use sentry_actix::ActixWebHubExt;
let hub = Hub::from_request(req);
Hub::run(hub, || {
sentry::capture_message("Something is not well", Level::Warning);
});
```

View File

@ -1,101 +0,0 @@
---
title: 服务器
menu: docs_basics
weight: 150
---
# HTTP服务器
该[**HttpServer**](../../actix-web/actix_web/server/struct.HttpServer.html)类型负责服务的HTTP请求。
`HttpServer`接受应用程序工厂作为参数并且应用程序工厂必须具有Send+ Sync边界。p
要绑定到特定的套接字地址, [`bind()`](../../actix-web/actix_web/server/struct.HttpServer.html#method.bind) 必须使用并且可能会多次调用它。绑定ssl套接字使用[`bind_ssl()`](../../actix-web/actix_web/server/struct.HttpServer.html#method.bind_ssl)或[`bind_tls()`](../../actix-web/actix_web/server/struct.HttpServer.html#method.bind_tls)。启动http服务器启动方法之一是
- use [`start()`](https://actix.rs/actix-web/actix_web/server/struct.HttpServer.html#method.start)
for a server
`HttpServer`是一位actix actor。它必须在正确配置的actix系统中初始化
{{< include-example example="server" section="main" >}}
> 可以使用该run()方法在单独的线程中启动服务器。在这种情况下服务器会产生一个新线程并在其中创建一个新的actix系统。要停止此服务器请发送`StopServer`消息。
`HttpServer`被实施为actix actor。可以通过消息传递系统与服务器进行通信。启动方法例如`start()`返回启动的http服务器的地址。它接受几种消息
- PauseServer - 暂停接受传入连接
- ResumeServer - 继续接受传入连接
- StopServer - 停止传入连接处理停止所有workers并退出
{{< include-example example="server" file="signals.rs" section="signals" >}}
## 多线程
`HttpServer`自动启动一些http worker默认情况下这个数量等于系统中逻辑CPU的数量。该数量可以用该[`HttpServer::workers()`](../../actix-web/actix_web/server/struct.HttpServer.html#method.workers)方法覆盖 。
{{< include-example example="server" file="workers.rs" section="workers" >}}
服务器为每个创建的worker创建一个单独的应用实例。应用程序状态不在线程之间共享。分享状态可以使用Arc。
>应用程序状态并不需要是Send和Sync但是工厂必须是Send+ Sync。
## SSL
有两种功能的ssl服务器`tls`和`alpn`。该tls功能由native-tls集成alpn由openssl。
```toml
[dependencies]
actix-web = { version = "{{< actix-version "actix-web" >}}", features = ["alpn"] }
```
{{< include-example example="server" file="ssl.rs" section="ssl" >}}
**注意**HTTP / 2.0协议需要[tls alpn](https://tools.ietf.org/html/rfc7301)。目前只有openssl有alpn支持。完整示例请查看[examples/tls](https://github.com/actix/examples/tree/master/tls).
要创建key.pem和cert.pem请使用以下命令。**Fill in your own subject**
```bash
$ openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem \
-days 365 -sha256 -subj "/C=CN/ST=Fujian/L=Xiamen/O=TVlinux/OU=Org/CN=muro.lxd"
```
要删除密码请将nopass.pem复制到key.pem
```bash
$ openssl rsa -in key.pem -out nopass.pem
```
## Keep-Alive
Actix可以等待keep-alive的请求。
》 *keep-alive*连接行为由服务器设置定义。
- `75`, `Some(75)`, `KeepAlive::Timeout(75)` - 75秒keep alive定时器。
- `None` or `KeepAlive::Disabled` - 禁用 *keep alive*.
- `KeepAlive::Tcp(75)` - 使用 `SO_KEEPALIVE` socket 选项.
{{< include-example example="server" file="ka.rs" section="ka" >}}
如果选择第一个选项,则*keep alive*状态根据响应的*connection-type*计算。默认情况下`HttpResponse::connection_type`未定义。在这种情况下, *keep alive* 状态由请求的http版本定义。
> *keep alive***关闭** 对于 *HTTP/1.0* 然而是 **打开** 对于 *HTTP/1.1**HTTP/2.0*.
*Connection type*可以用`HttpResponseBuilder::connection_type()`方法改变。
{{< include-example example="server" file="ka_tp.rs" section="example" >}}
## 优雅的关机
`HttpServer`支持优雅的关机。收到停止信号后workers会有特定的时间完成服务请求。任何在超时后仍然活着的workers工作线程都会被迫停止。默认情况下关机超时设置为30秒。您可以使用[`HttpServer::shutdown_timeout()`](../../actix-web/actix_web/server/struct.HttpServer.html#method.shutdown_timeout)方法更改此参数 。
您可以使用服务器地址向服务器发送停止消息,并指定是否要进行正常关机。[`start()`](../../actix-web/actix_web/server/struct.HttpServer.html#method.start)方法返回服务器的地址。
`HttpServer`处理几个OS信号。所有操作系统都提供CTRL-C其他信号在unix系统上可用。
- *SIGINT* - 强制关闭工作线程
- *SIGTERM* - 优雅的停止工作线程
- *SIGQUIT* - 制关闭 workers工作线程
> 可以用[`HttpServer::disable_signals()`](../../actix-web/actix_web/server/struct.HttpServer.html#method.disable_signals)
方法禁用信号处理 。

View File

@ -1,46 +0,0 @@
---
title: 静态文件
menu: docs_advanced
weight: 230
---
# 单文件
可以使用自定义路径模式和NamedFile来提供静态文件服务。要匹配路径尾部我们可以使用[.*]正则表达式。
```rust
use std::path::PathBuf;
use actix_web::{App, HttpRequest, Result, http::Method, fs::NamedFile};
fn index(req: HttpRequest) -> Result<NamedFile> {
let path: PathBuf = req.match_info().query("tail")?;
Ok(NamedFile::open(path)?)
}
fn main() {
App::new()
.resource(r"/a/{tail:.*}", |r| r.method(Method::GET).f(index))
.finish();
}
```
# 目录
StaticFiles可以用作特定目录和子目录文件服务。 StaticFiles必须注册一个App::handler()方法,否则它将无法服务子路径。
```rust
use actix_web::{App, fs};
fn main() {
App::new()
.handler(
"/static",
fs::StaticFiles::new(".")
.show_files_listing())
.finish();
}
```
该参数是根目录。默认情况下子目录的文件列表被禁用。尝试加载目录列表将返回404 Not Found响应。要启用文件列表请使用[* StaticFiles :: show_files_listing*](https://actix.rs/actix-web/actix_web/fs/struct.StaticFiles.html#method.show_files_listing) 方法。
与其显示目录的文件列表宁一种方法是重定向到特定的index文件。使用[*StaticFiles::index_file()*](https://actix.rs/actix-web/actix_web/fs/struct.StaticFiles.html#method.index_file)方法来配置此重定向。

View File

@ -1,236 +0,0 @@
---
title: Testing
menu: docs_advanced
weight: 210
---
# Testing
Every application should be well tested. Actix provides tools to perform unit and
integration tests.
# Unit Tests
For unit testing, actix provides a request builder type and a simple handler runner.
[*TestRequest*](../../actix-web/actix_web/test/struct.TestRequest.html)
implements a builder-like pattern.
You can generate a `HttpRequest` instance with `finish()`, or you can
run your handler with `run()` or `run_async()`.
```rust
use actix_web::{http, test, HttpRequest, HttpResponse, HttpMessage};
fn index(req: HttpRequest) -> HttpResponse {
if let Some(hdr) = req.headers().get(http::header::CONTENT_TYPE) {
if let Ok(s) = hdr.to_str() {
return HttpResponse::Ok().into()
}
}
HttpResponse::BadRequest().into()
}
fn main() {
let resp = test::TestRequest::with_header("content-type", "text/plain")
.run(index)
.unwrap();
assert_eq!(resp.status(), http::StatusCode::OK);
let resp = test::TestRequest::default()
.run(index)
.unwrap();
assert_eq!(resp.status(), http::StatusCode::BAD_REQUEST);
}
```
# Integration tests
There are several methods for testing your application. Actix provides
[*TestServer*](../../actix-web/actix_web/test/struct.TestServer.html), which can be used
to run the application with specific handlers in a real http server.
`TestServer::get()`, `TestServer::post()`, and `TestServer::client()`
methods can be used to send requests to the test server.
A simple form `TestServer` can be configured to use a handler.
`TestServer::new` method accepts a configuration function, and the only argument
for this function is a *test application* instance.
> Check the [api documentation](../../actix-web/actix_web/test/struct.TestApp.html)
> for more information.
```rust
use actix_web::{HttpRequest, HttpMessage};
use actix_web::test::TestServer;
use std::str;
fn index(req: HttpRequest) -> &'static str {
"Hello world!"
}
fn main() {
// start new test server
let mut srv = TestServer::new(|app| app.handler(index));
let request = srv.get().finish().unwrap();
let response = srv.execute(request.send()).unwrap();
assert!(response.status().is_success());
let bytes = srv.execute(response.body()).unwrap();
let body = str::from_utf8(&bytes).unwrap();
assert_eq!(body, "Hello world!");
}
```
The other option is to use an application factory. In this case, you need to pass the factory
function the same way as you would for real http server configuration.
```rust
use actix_web::{http, test, App, HttpRequest, HttpResponse};
fn index(req: HttpRequest) -> HttpResponse {
HttpResponse::Ok().into()
}
/// This function get called by http server.
fn create_app() -> App {
App::new()
.resource("/test", |r| r.h(index))
}
fn main() {
let mut srv = test::TestServer::with_factory(create_app);
let request = srv.client(
http::Method::GET, "/test").finish().unwrap();
let response = srv.execute(request.send()).unwrap();
assert!(response.status().is_success());
}
```
If you need more complex application configuration, use the `TestServer::build_with_state()`
method. For example, you may need to initialize application state or start `SyncActor`'s for diesel
interation. This method accepts a closure that constructs the application state,
and it runs when the actix system is configured. Thus, you can initialize any additional actors.
```rust
#[test]
fn test() {
let srv = TestServer::build_with_state(|| {
// we can start diesel actors
let addr = SyncArbiter::start(3, || {
DbExecutor(SqliteConnection::establish("test.db").unwrap())
});
// then we can construct custom state, or it could be `()`
MyState{addr: addr}
})
// register server handlers and start test server
.start(|app| {
app.resource(
"/{username}/index.html", |r| r.with(
|p: Path<PParam>| format!("Welcome {}!", p.username)));
});
// now we can run our test code
);
```
# Stream response tests
If you need to test stream it would be enough to convert a [*ClientResponse*](../../actix-web/actix_web/client/struct.ClientResponse.html) to future and execute it.
For example of testing [*Server Sent Events*](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events).
```rust
extern crate bytes;
extern crate futures;
extern crate actix_web;
use bytes::Bytes;
use futures::stream::poll_fn;
use futures::{Async, Poll, Stream};
use actix_web::{HttpRequest, HttpResponse, Error};
use actix_web::http::{ContentEncoding, StatusCode};
use actix_web::test::TestServer;
fn sse(_req: HttpRequest) -> HttpResponse {
let mut counter = 5usize;
// yields `data: N` where N in [5; 1]
let server_events = poll_fn(move || -> Poll<Option<Bytes>, Error> {
if counter == 0 {
return Ok(Async::NotReady);
}
let payload = format!("data: {}\n\n", counter);
counter -= 1;
Ok(Async::Ready(Some(Bytes::from(payload))))
});
HttpResponse::build(StatusCode::OK)
.content_encoding(ContentEncoding::Identity)
.content_type("text/event-stream")
.streaming(server_events)
}
fn main() {
// start new test server
let mut srv = TestServer::new(|app| app.handler(sse));
// request stream
let request = srv.get().finish().unwrap();
let response = srv.execute(request.send()).unwrap();
assert!(response.status().is_success());
// convert ClientResponse to future, start read body and wait first chunk
let (bytes, response) = srv.execute(response.into_future()).unwrap();
assert_eq!(bytes.unwrap(), Bytes::from("data: 5\n\n"));
// next chunk
let (bytes, _) = srv.execute(response.into_future()).unwrap();
assert_eq!(bytes.unwrap(), Bytes::from("data: 4\n\n"));
}
```
# WebSocket server tests
It is possible to register a *handler* with `TestApp::handler()`, which
initiates a web socket connection. *TestServer* provides the method `ws()`, which connects to
the websocket server and returns ws reader and writer objects. *TestServer* also
provides an `execute()` method, which runs future objects to completion and returns
result of the future computation.
The following example demonstrates how to test a websocket handler:
```rust
use actix_web::*;
use futures::Stream;
struct Ws; // <- WebSocket actor
impl Actor for Ws {
type Context = ws::WebsocketContext<Self>;
}
impl StreamHandler<ws::Message, ws::ProtocolError> for Ws {
fn handle(&mut self, msg: ws::Message, ctx: &mut Self::Context) {
match msg {
ws::Message::Text(text) => ctx.text(text),
_ => (),
}
}
}
fn main() {
let mut srv = test::TestServer::new(
|app| app.handler(|req| ws::start(req, Ws)));
let (reader, mut writer) = srv.ws().unwrap();
writer.text("text");
let (item, reader) = srv.execute(reader.into_future()).unwrap();
assert_eq!(item, Some(ws::Message::Text("text".to_owned())));
}
```

View File

@ -1,450 +0,0 @@
---
title: URL Dispatch
menu: docs_advanced
weight: 190
---
# URL Dispatch
URL dispatch provides a simple way for mapping URLs to `Handler` code using a simple pattern
matching language. If one of the patterns matches the path information associated with a request,
a particular handler object is invoked.
> A handler is a specific object that implements the
> `Handler` trait, defined in your application, that receives the request and returns
> a response object. More information is available in the
> [handler section](sec-4-handler.html).
# Resource configuration
Resource configuration is the act of adding a new resources to an application.
A resource has a name, which acts as an identifier to be used for URL generation.
The name also allows developers to add routes to existing resources.
A resource also has a pattern, meant to match against the *PATH* portion of a *URL*.
It does not match against the *QUERY* portion (the portion following the scheme and
port, e.g., */foo/bar* in the *URL* *http://localhost:8080/foo/bar?q=value*).
The [*App::route()*](../../actix-web/actix_web/struct.App.html#method.route) method provides
simple way of registering routes. This method adds a single route to application
routing table. This method accepts a *path pattern*,
*http method* and a handler function. `route()` method could be called multiple times
for the same path, in that case, multiple routes register for the same resource path.
{{< include-example example="url-dispatch" section="main" >}}
While *App::route()* provides simple way of registering routes, to access
complete resource configuration, different method has to be used.
The [*App::resource()*](../../actix-web/actix_web/struct.App.html#method.resource) method
adds a single resource to application routing table. This method accepts a *path pattern*
and a resource configuration function.
{{< include-example example="url-dispatch" file="resource.rs" section="resource" >}}
The *Configuration function* has the following type:
```rust
FnOnce(&mut Resource<_>) -> ()
```
The *Configuration function* can set a name and register specific routes.
If a resource does not contain any route or does not have any matching routes, it
returns *NOT FOUND* http response.
## Configuring a Route
Resource contains a set of routes. Each route in turn has a set of predicates and a handler.
New routes can be created with `Resource::route()` method which returns a reference
to new *Route* instance. By default the *route* does not contain any predicates, so matches
all requests and the default handler is `HttpNotFound`.
The application routes incoming requests based on route criteria which are defined during
resource registration and route registration. Resource matches all routes it contains in
the order the routes were registered via `Resource::route()`.
> A *Route* can contain any number of *predicates* but only one handler.
{{< include-example example="url-dispatch" file="cfg.rs" section="cfg" >}}
In this example, `HttpResponse::Ok()` is returned for *GET* requests.
If a request contains `Content-Type` header, the value of this header is *text/plain*,
and path equals to `/path`, Resource calls handle of the first matching route.
If a resource can not match any route, a "NOT FOUND" response is returned.
[*ResourceHandler::route()*](../../actix-web/actix_web/dev/struct.ResourceHandler.html#method.route) returns a
[*Route*](../../actix-web/actix_web/dev/struct.Route.html) object. Route can be configured with a
builder-like pattern. Following configuration methods are available:
* [*Route::filter()*](../../actix-web/actix_web/dev/struct.Route.html#method.filter)
registers a new predicate. Any number of predicates can be registered for each route.
* [*Route::f()*](../../actix-web/actix_web/dev/struct.Route.html#method.f) registers
handler function for this route. Only one handler can be registered.
Usually handler registration
is the last config operation. Handler function can be a function or closure
and has the type
`Fn(HttpRequest<S>) -> R + 'static`
* [*Route::h()*](../../actix-web/actix_web/dev/struct.Route.html#method.h) registers
a handler object that implements the `Handler` trait. This is
similar to `f()` method - only one handler can
be registered. Handler registration is the last config operation.
* [*Route::a()*](../../actix-web/actix_web/dev/struct.Route.html#method.a) registers
an async handler function for this route. Only one handler can be registered.
Handler registration is the last config operation. Handler function can
be a function or closure and has the type
`Fn(HttpRequest<S>) -> Future<Item = HttpResponse, Error = Error> + 'static`
# Route matching
The main purpose of route configuration is to match (or not match) the request's `path`
against a URL path pattern. `path` represents the path portion of the URL that was requested.
The way that *actix* does this is very simple. When a request enters the system,
for each resource configuration declaration present in the system, actix checks
the request's path against the pattern declared. This checking happens in the order that
the routes were declared via `App::resource()` method. If resource can not be found,
the *default resource* is used as the matched resource.
When a route configuration is declared, it may contain route predicate arguments. All route
predicates associated with a route declaration must be `true` for the route configuration to
be used for a given request during a check. If any predicate in the set of route predicate
arguments provided to a route configuration returns `false` during a check, that route is
skipped and route matching continues through the ordered set of routes.
If any route matches, the route matching process stops and the handler associated with
the route is invoked. If no route matches after all route patterns are exhausted, a *NOT FOUND* response get returned.
# Resource pattern syntax
The syntax of the pattern matching language used by actix in the pattern
argument is straightforward.
The pattern used in route configuration may start with a slash character. If the pattern
does not start with a slash character, an implicit slash will be prepended
to it at matching time. For example, the following patterns are equivalent:
```
{foo}/bar/baz
```
and:
```
/{foo}/bar/baz
```
A *variable part* (replacement marker) is specified in the form *{identifier}*,
where this means "accept any characters up to the next slash character and use this
as the name in the `HttpRequest.match_info()` object".
A replacement marker in a pattern matches the regular expression `[^{}/]+`.
A match_info is the `Params` object representing the dynamic parts extracted from a
*URL* based on the routing pattern. It is available as *request.match_info*. For example, the
following pattern defines one literal segment (foo) and two replacement markers (baz, and bar):
```
foo/{baz}/{bar}
```
The above pattern will match these URLs, generating the following match information:
```
foo/1/2 -> Params {'baz':'1', 'bar':'2'}
foo/abc/def -> Params {'baz':'abc', 'bar':'def'}
```
It will not match the following patterns however:
```
foo/1/2/ -> No match (trailing slash)
bar/abc/def -> First segment literal mismatch
```
The match for a segment replacement marker in a segment will be done only up to
the first non-alphanumeric character in the segment in the pattern. So, for instance,
if this route pattern was used:
```
foo/{name}.html
```
The literal path */foo/biz.html* will match the above route pattern, and the match result
will be `Params{'name': 'biz'}`. However, the literal path */foo/biz* will not match,
because it does not contain a literal *.html* at the end of the segment represented
by *{name}.html* (it only contains biz, not biz.html).
To capture both segments, two replacement markers can be used:
```
foo/{name}.{ext}
```
The literal path */foo/biz.html* will match the above route pattern, and the match
result will be *Params{'name': 'biz', 'ext': 'html'}*. This occurs because there is a
literal part of *.* (period) between the two replacement markers *{name}* and *{ext}*.
Replacement markers can optionally specify a regular expression which will be used to decide
whether a path segment should match the marker. To specify that a replacement marker should
match only a specific set of characters as defined by a regular expression, you must use a
slightly extended form of replacement marker syntax. Within braces, the replacement marker
name must be followed by a colon, then directly thereafter, the regular expression. The default
regular expression associated with a replacement marker *[^/]+* matches one or more characters
which are not a slash. For example, under the hood, the replacement marker *{foo}* can more
verbosely be spelled as *{foo:[^/]+}*. You can change this to be an arbitrary regular expression
to match an arbitrary sequence of characters, such as *{foo:\d+}* to match only digits.
Segments must contain at least one character in order to match a segment replacement marker.
For example, for the URL */abc/*:
* */abc/{foo}* will not match.
* */{foo}/* will match.
> **Note**: path will be URL-unquoted and decoded into valid unicode string before
> matching pattern and values representing matched path segments will be URL-unquoted too.
So for instance, the following pattern:
```
foo/{bar}
```
When matching the following URL:
```
http://example.com/foo/La%20Pe%C3%B1a
```
The matchdict will look like so (the value is URL-decoded):
```
Params{'bar': 'La Pe\xf1a'}
```
Literal strings in the path segment should represent the decoded value of the
path provided to actix. You don't want to use a URL-encoded value in the pattern.
For example, rather than this:
```
/Foo%20Bar/{baz}
```
You'll want to use something like this:
```
/Foo Bar/{baz}
```
It is possible to get "tail match". For this purpose custom regex has to be used.
```
foo/{bar}/{tail:.*}
```
The above pattern will match these URLs, generating the following match information:
```
foo/1/2/ -> Params{'bar':'1', 'tail': '2/'}
foo/abc/def/a/b/c -> Params{'bar':u'abc', 'tail': 'def/a/b/c'}
```
# Scoping Routes
Scoping helps you organize routes sharing common root paths. You can nest
scopes within scopes.
Suppose that you want to organize paths to endpoints used to manage a "Project",
consisting of "Tasks". Such paths may include:
- /project
- /project/{project_id}
- /project/{project_id}/task
- /project/{project_id}/task/{task_id}
A scoped layout of these paths would appear as follows
{{< include-example example="url-dispatch" file="scope.rs" section="scope" >}}
A *scoped* path can contain variable path segments as resources. Consistent with
unscoped paths.
You can get variable path segments from `HttpRequest::match_info()`.
`Path` extractor also is able to extract scope level variable segments.
# Match information
All values representing matched path segments are available in
[`HttpRequest::match_info`](../actix_web/struct.HttpRequest.html#method.match_info).
Specific values can be retrieved with
[`Params::get()`](../actix_web/dev/struct.Params.html#method.get).
Any matched parameter can be deserialized into a specific type if the type
implements the `FromParam` trait. For example most standard integer types
the trait, i.e.:
{{< include-example example="url-dispatch" file="minfo.rs" section="minfo" >}}
For this example for path '/a/1/2/', values v1 and v2 will resolve to "1" and "2".
It is possible to create a `PathBuf` from a tail path parameter. The returned `PathBuf` is
percent-decoded. If a segment is equal to "..", the previous segment (if
any) is skipped.
For security purposes, if a segment meets any of the following conditions,
an `Err` is returned indicating the condition met:
* Decoded segment starts with any of: `.` (except `..`), `*`
* Decoded segment ends with any of: `:`, `>`, `<`
* Decoded segment contains any of: `/`
* On Windows, decoded segment contains any of: '\'
* Percent-encoding results in invalid UTF8.
As a result of these conditions, a `PathBuf` parsed from request path parameter is
safe to interpolate within, or use as a suffix of, a path without additional checks.
{{< include-example example="url-dispatch" file="pbuf.rs" section="pbuf" >}}
List of `FromParam` implementations can be found in
[api docs](../../actix-web/actix_web/dev/trait.FromParam.html#foreign-impls)
## Path information extractor
Actix provides functionality for type safe path information extraction.
[*Path*](../../actix-web/actix_web/struct.Path.html) extracts information, destination type
could be defined in several different forms. Simplest approach is to use
`tuple` type. Each element in tuple must correpond to one element from
path pattern. i.e. you can match path pattern `/{id}/{username}/` against
`Path<(u32, String)>` type, but `Path<(String, String, String)>` type will
always fail.
{{< include-example example="url-dispatch" file="path.rs" section="path" >}}
It also possible to extract path pattern information to a struct. In this case,
this struct must implement *serde's *`Deserialize` trait.
{{< include-example example="url-dispatch" file="path2.rs" section="path" >}}
[*Query*](../../actix-web/actix_web/struct.Query.html) provides similar
functionality for request query parameters.
# Generating resource URLs
Use the [*HttpRequest.url_for()*](../../actix-web/actix_web/struct.HttpRequest.html#method.url_for)
method to generate URLs based on resource patterns. For example, if you've configured a
resource with the name "foo" and the pattern "{a}/{b}/{c}", you might do this:
{{< include-example example="url-dispatch" file="urls.rs" section="url" >}}
This would return something like the string *http://example.com/test/1/2/3* (at least if
the current protocol and hostname implied http://example.com).
`url_for()` method returns [*Url object*](https://docs.rs/url/1.7.0/url/struct.Url.html) so you
can modify this url (add query parameters, anchor, etc).
`url_for()` could be called only for *named* resources otherwise error get returned.
# External resources
Resources that are valid URLs, can be registered as external resources. They are useful
for URL generation purposes only and are never considered for matching at request time.
{{< include-example example="url-dispatch" file="url_ext.rs" section="ext" >}}
# Path normalization and redirecting to slash-appended routes
By normalizing it means:
* Add a trailing slash to the path.
* Double slashes are replaced by one.
The handler returns as soon as it finds a path that resolves
correctly. The order if all enable is 1) merge, 2) both merge and append
and 3) append. If the path resolves with
at least one of those conditions, it will redirect to the new path.
If *append* is *true*, append slash when needed. If a resource is
defined with trailing slash and the request doesn't have one, it will
be appended automatically.
If *merge* is *true*, merge multiple consecutive slashes in the path into one.
This handler designed to be used as a handler for application's *default resource*.
{{< include-example example="url-dispatch" file="norm.rs" section="norm" >}}
In this example `/resource`, `//resource///` will be redirected to `/resource/`.
In this example, the path normalization handler is registered for all methods,
but you should not rely on this mechanism to redirect *POST* requests. The redirect of the
slash-appending *Not Found* will turn a *POST* request into a GET, losing any
*POST* data in the original request.
It is possible to register path normalization only for *GET* requests only:
{{< include-example example="url-dispatch" file="norm2.rs" section="norm" >}}
## Using an Application Prefix to Compose Applications
The `App::prefix()` method allows to set a specific application prefix.
This prefix represents a resource prefix that will be prepended to all resource patterns added
by the resource configuration. This can be used to help mount a set of routes at a different
location than the included callable's author intended while still maintaining the same
resource names.
For example:
{{< include-example example="url-dispatch" file="prefix.rs" section="prefix" >}}
In the above example, the *show_users* route will have an effective route pattern of
*/users/show* instead of */show* because the application's prefix argument will be prepended
to the pattern. The route will then only match if the URL path is */users/show*,
and when the `HttpRequest.url_for()` function is called with the route name show_users,
it will generate a URL with that same path.
# Custom route predicates
You can think of a predicate as a simple function that accepts a *request* object reference
and returns *true* or *false*. Formally, a predicate is any object that implements the
[`Predicate`](../actix_web/pred/trait.Predicate.html) trait. Actix provides
several predicates, you can check
[functions section](../../actix-web/actix_web/pred/index.html#functions) of api docs.
Here is a simple predicate that check that a request contains a specific *header*:
{{< include-example example="url-dispatch" file="pred.rs" section="pred" >}}
In this example, *index* handler will be called only if request contains *CONTENT-TYPE* header.
Predicates have access to the application's state via `HttpRequest::state()`.
Also predicates can store extra information in
[request extensions](../../actix-web/actix_web/struct.HttpRequest.html#method.extensions).
## Modifying predicate values
You can invert the meaning of any predicate value by wrapping it in a `Not` predicate.
For example, if you want to return "METHOD NOT ALLOWED" response for all methods
except "GET":
{{< include-example example="url-dispatch" file="pred2.rs" section="pred" >}}
The `Any` predicate accepts a list of predicates and matches if any of the supplied
predicates match. i.e:
```rust
pred::Any(pred::Get()).or(pred::Post())
```
The `All` predicate accepts a list of predicates and matches if all of the supplied
predicates match. i.e:
```rust
pred::All(pred::Get()).and(pred::Header("content-type", "plain/text"))
```
# Changing the default Not Found response
If the path pattern can not be found in the routing table or a resource can not find matching
route, the default resource is used. The default response is *NOT FOUND*.
It is possible to override the *NOT FOUND* response with `App::default_resource()`.
This method accepts a *configuration function* same as normal resource configuration
with `App::resource()` method.
{{< include-example example="url-dispatch" file="dhandler.rs" section="default" >}}

View File

@ -1,44 +0,0 @@
---
title: Websockets
menu: docs_proto
weight: 240
---
Actix支持WebSockets开箱即用。可以使用[ws :: WsStream](https://actix.rs/actix-web/actix_web/ws/struct.WsStream.html)将请求的Payload转换为[ws :: Message](https://actix.rs/actix-web/actix_web/ws/enum.Message.html)流然后使用流组合器来处理实际的消息但处理websocket通信使用http actor更简单。
以下是一个简单的websocket echo server的例子
```rust
use actix::*;
use actix_web::*;
/// Define http actor
struct Ws;
impl Actor for Ws {
type Context = ws::WebsocketContext<Self>;
}
/// Handler for ws::Message message
impl StreamHandler<ws::Message, ws::ProtocolError> for Ws {
fn handle(&mut self, msg: ws::Message, ctx: &mut Self::Context) {
match msg {
ws::Message::Ping(msg) => ctx.pong(&msg),
ws::Message::Text(text) => ctx.text(text),
ws::Message::Binary(bin) => ctx.binary(bin),
_ => (),
}
}
}
fn main() {
App::new()
.resource("/ws/", |r| r.f(|req| ws::start(req, Ws)))
.finish();
}
```
[websocket directory](https://github.com/actix/examples/tree/master/websocket/)提供了一个简单的websocket echo server示例 。
[websocket-chat directory](https://github.com/actix/examples/tree/master/websocket-chat/)提供了一个聊天服务器可以通过websocket或tcp连接进行聊天

View File

@ -1,15 +0,0 @@
---
title: 何为Actix
menu: docs_intro
weight: 100
---
# Actix 指多种事情
Actix是一个强大的Rust的actor系统, 在它之上是actix-web框架。这是你在工作中大多使用的东西。Actix-web给你提供了一个有趣且快速的Web开发框架。
我们称actix-web为小而务实的框架。对于所有的意图和目的来说这是一个有少许曲折的微框架。如果你已经是一个Rust程序员你可能会很快熟悉它但即使你是来自另一种编程语言你应该会发现actix-web很容易上手。
使用actix-web开发的应用程序将在本机可执行文件中包含HTTP服务器。你可以把它放在另一个像nginx这样的HTTP服务器上。即使完全不存在另一个HTTP服务器的情况下actix-web也足以提供HTTP 1和HTTP 2支持以及SSL/TLS。这对于构建小型服务分发非常有用。
最重要的是actix-web可以稳定发布。

View File

@ -1,10 +0,0 @@
[home]
other = "首页"
[docs]
other = "文档"
[blog]
other = "博客"
[community]
other = "社区"
[code]
other = "源码"

View File

@ -1,63 +0,0 @@
{{ partial "header" . }}
{{ $currentURL := .URL }}
<div class="actix-pageheader">
<div class="container">
<h1 id="blog-title" class="display-4">{{ .Title }}</h1>
{{ if .Description }}
<p class="lead">{{ .Description }}</p>
{{ end }}
</div>
</div>
<div class="container actix-blog">
<div class="row">
<div class="col-md-3">
<button class="btn doctoggle" type="button" data-toggle="collapse" data-target="#collapsing-docnav" aria-expanded="false" aria-controls="collapsing-docnav">
Toggle navigation
</button>
<nav class="leftnav collapse show" id="collapsing-docnav">
<div class="" id="">
<details>
<summary>Introduction</summary>
<div>
<ul class="nav">
{{ range .Site.Menus.blog_intro }}
<li{{ if eq $currentURL .URL }} class="active"{{ end }}>
<a href="{{ .URL }}">{{ .Name }}</a>
</li>
{{ end }}
</ul>
</div>
</details>
<details>
<summary>2018</summary>
<div>
<ul class="nav">
{{ range .Site.Menus.blog_2018 }}
<li{{ if eq $currentURL .URL }} class="active"{{ end }}>
<a href="{{ .URL }}">{{ .Name }}</a>
</li>
{{ end }}
</ul>
</div>
</details>
</div>
</nav>
</div>
<div class="col-md-9">
<div class="actix-content">
{{ block "main" . }}{{ end }}
<!-- Yes, we have to use *Prev* to get the next content, because the
weights are sorted inversely to how they are actually displayed... -->
{{ with .PrevInSection }}<div class="actix-next"><b>Next up</b>: <a href = {{ .URL }}>{{ end }}
{{ with .PrevInSection }} {{ .Title }}</a></div>{{ end }}
</div>
</div>
</div>
</div>
{{ partial "footer" . }}

View File

@ -1,3 +0,0 @@
{{ define "main" }}
{{ .Content }}
{{ end }}

View File

@ -1,3 +0,0 @@
{{ define "main" }}
{{ .Content }}
{{ end }}

View File

@ -1,149 +0,0 @@
{{ partial "header" . }}
<div id="act-home">
<div class="jumbotron">
<div class="actix-jumbotron">
<img src="/img/logo-large.png" class="align-middle actix-logo" alt="">
<p class="lead">Rust强大的actor系统和有趣的web框架</p>
</div>
</div>
<div class="container actix-home">
<div class="row">
<div class="col-md-4">
<div class="actix-features">
<h2>
<i class="fa fa-fw fa-shield" aria-hidden="true"></i>
类型安全
</h2>
<p>忘记关于字符串类型的对象,从请求到响应,一切都有类型,异步。</p>
<h2>
<i class="fa fa-fw fa-battery-full" aria-hidden="true"></i>
特性丰富
</h2>
<p>Actix提供了丰富的特性开箱即用。WebSocketsHTTP/2管道SSL异步HTTTP客户端等一应俱全.</p>
<h2>
<i class="fa fa-fw fa-puzzle-piece" aria-hidden="true"></i>
扩展性强
</h2>
<p>轻松创建任何基于Actix应用的自己的特色库。</p>
<h2>
<i class="fa fa-fw fa-dashboard" aria-hidden="true"></i>
速度极快
</h2>
<p>Actix 具有顶级的速度. <a href="https://www.techempower.com/benchmarks/#section=data-r16&hw=ph&test=plaintext">Check yourself</a>.</p>
</div>
</div>
<div class="col-md-8">
<div class="actix-content">
{{ highlight `extern crate actix_web;
use actix_web::{http::Method, server, App, Path, Responder};
fn index(info: Path<(u32, String)>) -> impl Responder {
format!("Hello {}! id:{}", info.1, info.0)
}
fn main() {
server::new(
|| App::new()
.route("/{id}/{name}/index.html", Method::GET, index))
.bind("127.0.0.1:8080").unwrap()
.run();
}` "rust" "" }}
</div>
</div>
</div>
<div class="actix-showcase">
<div class="col-md-9">
<div class="actix-feature" id="responders">
<h2>灵活的请求响应</h2>
<p>
Actix中的Handler函数可以返回实现该<code>Respondert</code> rait的各种对象。这使得从API返回一致的响应变得轻而易举。
</p>
{{ highlight `#[derive(Serialize)]
struct Measurement {
temperature: f32,
}
fn hello_world() -> impl Responder {
"Hello World!"
}
fn current_temperature(_req: HttpRequest) -> impl Responder {
Json(Measurement { temperature: 42.3 })
}` "rust" "" }}
</div>
<div class="actix-feature" id="extractors">
<h2>强大的Extractors</h2>
<p>
Actix提供了一个强大的提取器系统可以从传入的HTTP请求中提取数据并将其传递给您的视图函数。这不仅可以创建方便的API
而且还意味着您的视图函数可以是同步代码并且仍然可以受益于异步IO处理。
</p>
{{ highlight `#[derive(Deserialize)]
struct Event {
timestamp: f64,
kind: String,
tags: Vec<String>,
}
fn capture_event(evt: Json<Event>) -> impl Responder {
let id = store_event_in_db(evt.timestamp, evt.kind, evt.tags);
format!("got event {}", id)
}` "rust" "" }}
</div>
<div class="actix-feature" id="forms">
<h2>轻松处理表单</h2>
<p>
处理multipart/ urlencoded表单数据很容易。只需定义一个可以反序列化的结构actix就可以处理剩下的部分。
</p>
{{ highlight `#[derive(Deserialize)]
struct Register {
username: String,
country: String,
}
fn register(data: Form<Register>) -> impl Responder {
format!("Hello {} from {}!", data.username, data.country)
}` "rust" "" }}
</div>
<div class="actix-feature" id="routing">
<h2>请求路由</h2>
<p>
一个actix应用程序带有一个URL路由系统可以让你在URL上匹配并调用单个处理程序。为了获得额外的灵活性可以使用域。
</p>
{{ highlight `fn index(req: HttpRequest) -> impl Responder {
"Hello from the index page"
}
fn hello(path: Path<String>) -> impl Responder {
format!("Hello {}!", *path)
}
fn main() {
App::new()
.resource("/", |r| r.method(Method::Get).with(index))
.resource("/hello/{name}", |r| r.method(Method::Get).with(hello))
.finish();
}` "rust" "" }}
</div>
</div>
<div class="col-md-3 actix-feature-selectors">
<ul class="act-menu">
<li class="actix-feature-selector"><a href="#responders">灵活的请求响应</a></li>
<li class="actix-feature-selector"><a href="#extractors">强大的Extractors</a></li>
<li class="actix-feature-selector"><a href="#forms">轻松处理表单</a></li>
<li class="actix-feature-selector"><a href="#routing">请求路由</a></li>
</ul>
</div>
</div>
</div>
</div>
{{ partial "footer" . }}

View File

@ -13,7 +13,7 @@
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js" integrity="sha384-3ceskX3iaEnIogmQchP8opvBy3Mi7Ce34nWjpBIwVTHfGYWQS9jwHDVRnpKKHJg7" crossorigin="anonymous"></script> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js" integrity="sha384-3ceskX3iaEnIogmQchP8opvBy3Mi7Ce34nWjpBIwVTHfGYWQS9jwHDVRnpKKHJg7" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/tether/1.3.7/js/tether.min.js" integrity="sha384-XTs3FgkjiBgo8qjEjBk0tGmf3wPrWtA6coPfQDfFEY8AnYJwjalXCiosYRBIBZX8" crossorigin="anonymous"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/tether/1.3.7/js/tether.min.js" integrity="sha384-XTs3FgkjiBgo8qjEjBk0tGmf3wPrWtA6coPfQDfFEY8AnYJwjalXCiosYRBIBZX8" crossorigin="anonymous"></script>
<script src="/js/bootstrap.min.js"></script> <script src="/js/bootstrap.min.js"></script>
<script src="/js/actix.js" async></script> <script src="/js/actix.js"></script>
{{ template "_internal/google_analytics.html" . }} {{ template "_internal/google_analytics.html" . }}
</body> </body>
</html> </html>

View File

@ -36,9 +36,6 @@
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" href="{{ "/docs/" | absLangURL }}">{{ T "docs" }}</a> <a class="nav-link" href="{{ "/docs/" | absLangURL }}">{{ T "docs" }}</a>
</li> </li>
<li class="nav-item" id="nav-blog">
<a class="nav-link" href="{{ "/blog/" | absLangURL }}">{{ T "blog" }}</a>
</li>
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" href="{{ "/community/" | absLangURL }}">{{ T "community" }}</a> <a class="nav-link" href="{{ "/community/" | absLangURL }}">{{ T "community" }}</a>
</li> </li>
@ -51,6 +48,7 @@
{{ range $.Site.Home.AllTranslations }} {{ range $.Site.Home.AllTranslations }}
<li class="submenu-item"><a href="{{ .Permalink }}">{{ .Language.LanguageName }}</a></li> <li class="submenu-item"><a href="{{ .Permalink }}">{{ .Language.LanguageName }}</a></li>
{{ end }} {{ end }}
<li ><a href="https://actix-cn.github.io/">中文</a></li>
</ul> </ul>
</li> </li>
</ul> </ul>

View File

@ -171,9 +171,7 @@ img {
padding-top: 0; padding-top: 0;
list-style: none; list-style: none;
} }
.navbar-nav #nav-blog {
display: none;
}
.navbar-nav .language-selector { .navbar-nav .language-selector {
position: relative; position: relative;
} }
@ -405,22 +403,6 @@ img {
text-decoration: none; text-decoration: none;
} }
/*
*
* ===== blog =====
*
*/
#collapsing-docnav details {
border: none;
}
#collapsing-docnav details summary {
font-size: 1.2rem;
font-weight: bold;
margin-bottom: 0.8rem;
}
#collapsing-docnav details ul {
margin: 1rem;
}
/* /*
* *

View File

@ -37,9 +37,3 @@
}); });
})(); })();
window.onload = function(){
if (window.location.href.search("cn") != -1) {
document.getElementById("nav-blog").style.display = "inline"
}
}