5分钟APIG实战: 使用Rust语言快速构建API能力开放
序言:Rust语言简介
参与过C/C++大型项目的同学可能都经历过因为Null Pointer、Memory Leak等问题“被” 加班了不知道多少个晚上。别沮丧,你不是一个人,Mozilla Firefox的开发者们同样经历过这个问题。浏览器可以说是我们日常使用最为频繁的软件了,目前主流的浏览器主要有Google Chrome、Internet Explorer、Mozilla Firefox。为了提升用户体验,Mozilla就已经启动了多线程渲染的计划。然而,面对大型的C/C++工程,Mozilla的开发者们也坚持不住了。此时,Rust进入了开发者的眼中,与C语言ABI兼容、多编程范式支持、无GC及独特的所有权系统,使得Mozilla与Rust语言一拍即合,并迅速启动了 Mozilla 的下一代浏览器引擎项目:servo,到目前为止(2018年8 月),servo已经成为了除Rust编译器自身外,社区中最大的Rust项目。servo目前已经部 分应用在Firefox 57之后的版本中。
Rust语言的设计目标是安全、高效、并发以及实用性。Rust 从一定程度上解决了C++的以 下痛点:
1容器/数组越界访问;
2动态内存分配的泄露与double free问题;
3难以对依赖进行管理。
其中前两点在C/C++项目中是最容易引发Bug以及安全问题的原因,依靠人来对这些问题进行检查往往不是最佳的解决方案。Rust通过其独特的所有权系统,简化所研究的对象,使得一些隐晦的问题在编译期间便暴露出来。任何事情都是有两面性的,由于严格的编译期检查以及工程实现上的取舍,Rust在一定程度上牺牲了编译速度以及灵活性,对“灵活性”的舍弃并不代表Rust语言的表现力下降,只是我们在编写Rust程序时,可能需要改变一下以往的思路。
在Rust圈子中,有一句调侃:“C++是调试的时候想撞墙,而Rust是编译的时候想撞墙”。接下来我们将通过一个简单的例子来建立Rust中所有权系统的一个基本印象。
核心概念:所有权系统
Rust 的所有权系统包括三个核心概念:所有权、借用以及生命周期。我们首先来通过一个 简单的例子来建立对所有权以及生命周期的直观概念。
#[derive(Debug)]
struct Foo;
fn main() {
let foo = Foo; // Note: Foo not implement Copy trait
let bar = foo;
println!("{:?}", bar);
// println!("{:?}", foo);
}
首先创建了一个Foo类型的变量foo,然后我们执行let bar = foo;,然后我们尝试输出这两个变量的值,如果我们将第9行的注释去掉,程序将无法通过编译,这是因为在 Rust中,对于没有实现Copy trait的类型,如果我们将一个绑定赋给另一个绑定,默认使用的是move语义,也即对于任意给定的资源,当且仅当有一个变量绑定与之对应。
想要进一步学习Rust的小哥哥小姐姐,可以参考Rust Learning(https://github.com/ctjhoa/rust-learning)
使用Rust进行HTTP Web后端应用开发
在Rust生态中进行HTTP Web后端应用开发目前主要依赖两个基础库:http 以及hyper,其中 http 提供HTTP标准相关的基础类型,如Request<T> 、Response<T>以及StatusCode和常用的Header等;hyper的定位是一个高效、准确的 HTTP底层库,它封装了HTTP的报文解析、报文编码处理、连接控制等内容,对于用户而言只需要实现一个类似于Fn(Request) -> Response的映射,就可以完成HTTP Web服务端的开发。
基于http以及hyper,社区中还有很多用于Web应用开发的框架,常用的有:
➤rocket
➤iron
➤actix-web
➤tower-web
值得一提的是上周刚发布的tower-web,因为这是官方net团队2018年工作计划的一部分, 这个库在未来会为Rust生态提供一个灵活、高效、易于使用的Web开发框架。那么事不宜迟, 我们通过实战演练来一睹为快。
在本月月底,tower-web将会集成到warp项目中,成为warp框架的一部分,开发的重心将会转移到warp上。
实战演练
登录华为云,并创建弹性云服务器作为我们的后端应用服务器:

实战中使用的系统版本为Ubuntu 16.04,如果选择不同的系统需要根据情况调整命令。
安装相关的工具链
apt update && apt install build-essential
# 安装Rust工具链
curl https://sh.rustup.rs -sSf | sh
这一步结束后,我们就可以开始编写我们的应用服务了。
编写后端Web应用
这次分享我们来构建一个RESTful中文分词API,首先我们来创建一个Rust工程 cargo new --bin chinese_segmentation
接下来在Cargo.toml中添加相关
[dependencies]
tower-web = "0.2"
# Jieba Chinese Work Segmentation
jieba-rs = "0.2"
# logging utils
log = "0.4.0"
env_logger = "0.5.12"
# Serializing responses, deserializing requests
serde = "1.0.70"
然后是我们的main.rs,与其他语言一样,在文件开始的部分引入外部依赖以及相关声明:
extern crate jieba_rs;
#[macro_use]
extern crate tower_web;
#[macro_use]
extern crate log;
extern crate env_logger;
use std::iter::FromIterator;
use std::collections::HashSet;
use jieba_rs::Jieba;
use tower_web::ServiceBuilder;
接下来我们定义我们的服务资源ChineseTokenizer:
#[derive(Debug)]
struct ChineseTokenizer {
inner: Jieba,
}
impl ChineseTokenizer {
pub fn new() -> ChineseTokenizer {
ChineseTokenizer { inner: Jieba::new() }
}
// 对传入的字符串进行分词,并返回一个字符串向量
pub fn cut(&self, text: &String) -> Vec<String> {
let words = self.inner.cut(&text, true)
.into_iter()
.map(|word| word.to_owned())
.collect::<HashSet<String>>();
let mut words = Vec::from_iter(words.into_iter());
// 由于使用HashSet进行去重会引入不确定性,
// 因此对结果进行重排,使输出的结果有序。
words.sort();
words
}
}
定义了我们的服务资源后,我们来定义输入Web API的输入输出类型:
#[derive(Debug, Extract)]
struct TokenizeRequest {
text: String
}
#[derive(Debug, Response)]
#[web(status = "200")] // 当 handler 返回 Ok(xx) 时,返回 200 状态码
struct TokenizeResponse {
words: Vec<String>,
}
到目前为止,我们已经有了我们的服务资源,输入输出类型,接下来就到我们的重头戏了, Web 部分的实现,别担心,因为真的很简单。
impl_web! {
impl ChineseTokenizer {
#[post("/tokenize")]
#[content_type("application/json")]
fn tokenize(&self, body: TokenizeRequest) -> Reqult<TokenizeResponse, ()> {
Ok(TokenizeResponse {
words: self.cut(&body.text),
})
}
}
}
最后是我们的main函数:
fn main() {
// 初始化Logger
env_logger::init();
let addr = "0.0.0.0:8081".parse().expect("invalid address");
info!("listening on http://{}", addr);
ServiceBuilder::new()
.resource(ChineseTokenizer::new()) // 注册我们的服务资源
.run(&addr) // 让我们的服务跑起来
.unwrap();
}
现在,我们通过命令RUST_LOG=chinese_segmentation=info cargo run --release来检验 一下我们的成果了。服务在本地跑起来之后,我们可以通过命令 curl -H "Content-Type: application/json" -X POST -d '{"text":"中间件小哥"}' <url> 来测试一下我们的接口。
本地测试通过之后,就需要着手开始部署了,我们检查一下弹性云服务器的安全组的入方向 是否放开8081端口。
API 部署
API网关集成了监控、流控、负载均衡等一系列功能,为开发者提供高性能、高可用的API 托管服务,在本次实践中,我们将我们的API部署在API网关中。
1、登录华为云API网关服务,选择“新建API”

2、填写API的基本信息。
在本次实验中,选择无认证。
3、定义API请求。
请求路径填为 /segment,方法为 POST。
4、定义后端服务。
请求方式设置为POST,在VPC通道这一项中,我们需要新建VPC通道。端口设置为8081, 并将其与弹性云服务器关联。
创建完VPC通道后,回到API创建页面,填入相关信息:
网关创建完成后,我们需要回到我们的弹性云服务器,将我们的后端服务器先跑起来:
RUST_LOG=chinese_segmentation=info nohup ./target/release/chinese_segmentation 2>&1 ~/api.log &
作为示例,这里使用nohup命令来跑我们的服务。但在生产环境中,建议使用 systemd等工具来跑服务。服务在云服务器运行起来之后,将API发布至RELEASE环境中。
然后我们就可以和我们的API愉快地玩耍啦。
5分钟APIG实战: 使用Rust语言快速构建API能力开放的更多相关文章
- 基于Go语言快速构建RESTful API服务
In this post, we will not only cover how to use Go to create a RESTful JSON API, but we will also ta ...
- Rust语言之HelloWorld Web版
Rust语言之HelloWorld Web版 下面这篇文章值得仔细研读: http://arthurtw.github.io/2014/12/21/rust-anti-sloppy-programmi ...
- ElasticSearch实战系列六: Logstash快速入门和实战
前言 本文主要介绍的是ELK日志系统中的Logstash快速入门和实战 ELK介绍 ELK是三个开源软件的缩写,分别表示:Elasticsearch , Logstash, Kibana , 它们都是 ...
- Swift语言快速入门
Swift语言快速入门(首部同步新版官方API文档和语法的Swift图书,确保代码可编译,作者专家在线答疑,图书勘误实时跟进) 极客学院 编著 ISBN 978-7-121-24328-8 201 ...
- Rust语言:安全地并发
http://www.csdn.net/article/2014-02-26/2818556-Rust http://www.zhihu.com/question/20032903 Rust是近两年M ...
- D、GO、Rust 谁会在未来取代 C?为什么?——Go语言的定位非常好,Rust语言非常优秀,D语言也不错
不要管我的地位和 D 语言创造者之一的身份.我会坦诚的回答这个问题.我熟悉 Go 和 Rust,并且知道 D 的缺点在哪里.我鼓励人们在 Rust 和 Go 社区相似身份的人,也可以提出他们诚恳的观点 ...
- 关于《Selenium3自动化测试实战--基于python语言》
2016年1月,机缘巧合下我出版了<Selenium2自动化测试实战--基于python语言>这本书,当时写书的原因是,大部分讲Selenium的书并不讲编程语言和单元测试框,如果想在项目 ...
- selenium2自动化测试实战--基于Python语言
自动化测试基础 一. 软件测试分类 1.1 根据项目流程阶段划分软件测试 1.1.1 单元测试 单元测试(或模块测试)是对程序中的单个子程序或具有独立功能的代码段进行测试的过程. 1.1.2 集成测试 ...
- 学习Rust第一天 Rust语言特点
学习Rust之前,我觉得应该首先了解Rust语言的设计目的是什么?为什么会诞生这门语言?这门语言和其他的语言有什么不同. Rust语言的设计特点 高性能:rust拥有和C++相近的性能表现,所以在嵌入 ...
随机推荐
- React组件的防呆机制(propTypes)
Prop验证 随着应用不断变大,为了保证组件被正确使用变得越来越重要.为此我们引入propsTypes.React.PropTypes提供很多验证器(valodator)来验证传入的数据的有效性.当向 ...
- Props、State、Refs 与表单处理
我们也了解到 React Component 事实上可以视为显示 UI 的一个状态机(state machine),而这个状态机根据不同的 state(透过 setState() 修改)和 props ...
- 华硕(ASUS)X554LP笔记本一开机就进入aptio setup utility 问题的解决
某次因大意一直未插电,华硕(ASUS)X554LP笔记本后来没电关机.后来每次一开机就进入aptio setup utility界面,按F9调入默认配置,F10保存后退出,重启仍然进入aptio se ...
- 【译】x86程序员手册22-6.4页级保护
6.4 Page-Level Protection 页级保护 Two kinds of protection are related to pages: 与页相关的保护有两类: Restriction ...
- (转) 淘淘商城系列——使用SolrJ查询索引库
http://blog.csdn.net/yerenyuan_pku/article/details/72908538 我们有必要在工程中写查询索引库的代码前先进行必要的测试.我们先到Solr服务页面 ...
- @objc and dynamic
@objc and dynamic Objective-C runtime visibility and the depths of dynamic dispatch in the modern ...
- R中矩阵运算
# 数据产生 # rnorm(n, mean = 0, sd = 1) 正态分布的随机数(r 代表随机,可以替换成dnorm, pnorm, qnorm 作不同计算.r= random = 随机, d ...
- UVA - 11175 From D to E and Back(思路)
题目: 思路: 如图E:图中a.b.c.d是有向图D中的顶点,如果ac.bc都指向cd,而ac又指向ce,那bc同样应该有一条指向ce的边不然就不能从图D转换来.所以直接枚举顶点就可以了. 代码: # ...
- <SpringMvc>入门六 异常处理
如果不做异常处理,那么一直将错误向上抛出,则会最后在页面上显示错误代码 服务启动后,访问test1方法,页面会报500 为了提示友好的错误页面,所以需要做异常处理 1.编写自定义异常类(做提示信息的) ...
- Python爬虫入门教程: 半次元COS图爬取
半次元COS图爬取-写在前面 今天在浏览网站的时候,忽然一个莫名的链接指引着我跳转到了半次元网站 https://bcy.net/ 打开之后,发现也没有什么有意思的内容,职业的敏感让我瞬间联想到了 c ...