鍍金池/ 教程/ Java/ rust web 開發(fā)
標(biāo)準(zhǔn)輸入與輸出
消息傳遞
循環(huán)
注釋
Rust for Mac OS
幾種智能指針
Cell, RefCell
trait對象 (trait object)
rust web 開發(fā)
Unsafe、原始指針
Macro
迭代器
函數(shù)
Borrow, BorrowMut, ToOwned
快速上手
二叉樹
編輯器
測試與評測
Deref
安裝Rust
哈希表 HashMap
原生類型
17.錯誤處理
VS Code 安裝配置
動態(tài)數(shù)組Vec
模式匹配
操作符和格式化字符串
Rust for Linux
函數(shù)參數(shù)
Visual Studio
vim/GVim安裝配置
閉包作為參數(shù)和返回值
安全(Safety)
Cow
生命周期( Lifetime )
閉包的實(shí)現(xiàn)
所有權(quán)(Ownership)
Atom
將Rust編譯成庫
類型、運(yùn)算符和字符串
類型系統(tǒng)中的幾個常見 trait
特性
屬性和編譯器參數(shù)
Spacemacs
集合類型
Rust json處理
Heap & Stack
并行
標(biāo)準(zhǔn)庫示例
基本程序結(jié)構(gòu)
鏈表
trait 和 trait對象
前期準(zhǔn)備
代碼風(fēng)格
編譯器參數(shù)
基于語義化版本的項(xiàng)目版本聲明與管理
Rust 版本管理工具: rustup
引用&借用(References&Borrowing)
注釋與文檔
10.1 trait關(guān)鍵字
模式
調(diào)用ffi函數(shù)
unsafe
并發(fā),并行,多線程編程
AsRef 和 AsMut
Rust旅程
Rust for Windows
結(jié)構(gòu)體與枚舉
條件分支
附錄I-術(shù)語表
變量綁定與原生類型
Mutex 與 RwLock
泛型
裸指針
常用數(shù)據(jù)結(jié)構(gòu)實(shí)現(xiàn)
系統(tǒng)命令:調(diào)用grep
Into/From 及其在 String 和 &str 互轉(zhuǎn)上的應(yīng)用
共享內(nèi)存
Sublime
網(wǎng)絡(luò)模塊:W貓的回音
函數(shù)返回值
包和模塊
高階函數(shù)
函數(shù)與方法
match關(guān)鍵字
隊(duì)列
目錄操作:簡單grep
語句和表達(dá)式
并發(fā)編程
閉包
測試
閉包的語法
同步
迭代器
String
Send 和 Sync
Rc 和 Arc
屬性
Emacs
優(yōu)先隊(duì)列
Prelude
cargo簡介
控制流(control flow)
數(shù)組、動態(tài)數(shù)組和字符串
FFI
模塊和包系統(tǒng)、Prelude
實(shí)戰(zhàn)篇
Rust 是一門系統(tǒng)級編程語言,被設(shè)計(jì)為保證內(nèi)存和線程安全,并防止段錯誤。作為系統(tǒng)級編程語言,它的基本理念是 “零開銷抽象”。理
運(yùn)算符重載
Any和反射
rust數(shù)據(jù)庫操作
輸入輸出流
復(fù)合類型
性能測試

rust web 開發(fā)

rust既然是系統(tǒng)級的編程語言,所以當(dāng)然也能用來開發(fā) web,不過想我這樣凡夫俗子,肯定不能從頭自己寫一個 web 服務(wù)器,肯定要依賴已經(jīng)存在的 rust web開發(fā)框架來完成 web 開發(fā)。

rust目前比較有名的框架是iron和nickel,我們兩個都寫一下簡單的使用教程。

iron

接上一篇,使用cargo獲取第三方庫。cargo new mysite --bin

在cargo.toml中添加iron的依賴,

[dependencies]
iron = "*"

然后build將依賴下載到本地 cargo build

如果報(bào)ssl錯誤,那可能你需要安裝linux的ssl開發(fā)庫。

首先還是從 hello world 開始吧,繼續(xù)抄襲官方的例子:

extern crate iron;

use iron::prelude::*;
use iron::status;

fn main() {
    Iron::new(|_: &mut Request| {
        Ok(Response::with((status::Ok, "Hello World!")))
    }).http("localhost:3000").unwrap();
}

然后運(yùn)行

cargo run

使用curl直接就可以訪問你的網(wǎng)站了。

curl localhost:3000

Hello World!

仔細(xì)一看,發(fā)現(xiàn)這個例子很無厘頭啊,對于習(xí)慣了寫python的我來說,確實(shí)不習(xí)慣。 簡單點(diǎn)看:

iron::new().http("localhost:3000").unwrap() 這句是服務(wù)器的基本的定義,new內(nèi)部是一個rust lambda 表達(dá)式

let plus_one = |x: i32| x + 1;

assert_eq!(2, plus_one(1));

具體的怎么使用 ,可以暫時不用理會,因?yàn)槟阒灰廊绾瓮瓿蓋eb,因?yàn)槲乙膊粫??!?結(jié)合之前一章節(jié)的json處理,我們來看看web接口怎么返回json,當(dāng)然也要 rustc_serialize 放到 cargo.toml 中

下面的代碼直接參考開源代碼地址

extern crate iron;
extern crate rustc_serialize;

use iron::prelude::*;
use iron::status;
use rustc_serialize::json;

#[derive(RustcEncodable)]
struct Greeting {
    msg: String
}

fn main() {
    fn hello_world(_: &mut Request) -> IronResult<Response> {
        let greeting = Greeting { msg: "Hello, World".to_string() };
        let payload = json::encode(&greeting).unwrap();
        Ok(Response::with((status::Ok, payload)))
    }

    Iron::new(hello_world).http("localhost:3000").unwrap();
    println!("On 3000");
}

執(zhí)行 cargo run 使用 curl 測試結(jié)果:

curl localhost:3000
{"msg":"Hello, World"}

當(dāng)然可以可以實(shí)現(xiàn)更多的業(yè)務(wù)需求,通過控制自己的json。

既然有了json了,如果要多個路由什么的,豈不是完蛋了,所以不可能這樣的,我們需要考慮一下怎么實(shí)現(xiàn)路由的定制

不說話直接上代碼,同一樣要在你的cargo.toml文件中添加對router的依賴

extern crate iron;
extern crate router;
extern crate rustc_serialize;

use iron::prelude::*;
use iron::status;
use router::Router;
use rustc_serialize::json;

#[derive(RustcEncodable, RustcDecodable)]
struct Greeting {
    msg: String
}

fn main() {
    let mut router = Router::new();

    router.get("/", hello_world);
    router.post("/set", set_greeting);

    fn hello_world(_: &mut Request) -> IronResult<Response> {
        let greeting = Greeting { msg: "Hello, World".to_string() };
        let payload = json::encode(&greeting).unwrap();
        Ok(Response::with((status::Ok, payload)))
    }

    // Receive a message by POST and play it back.
    fn set_greeting(request: &mut Request) -> IronResult<Response> {
        let payload = request.body.read_to_string();
        let request: Greeting = json::decode(payload).unwrap();
        let greeting = Greeting { msg: request.msg };
        let payload = json::encode(&greeting).unwrap();
        Ok(Response::with((status::Ok, payload)))
    }

    Iron::new(router).http("localhost:3000").unwrap();
}

這次添加了路由的實(shí)現(xiàn)和獲取客戶端發(fā)送過來的數(shù)據(jù),有了get,post,所以現(xiàn)在一個基本的api網(wǎng)站已經(jīng)完成了。不過 并不是所有的網(wǎng)站都是api來訪問,同樣需要html模版引擎和直接返回靜態(tài)頁面。等等

vagrant@ubuntu-14:~/tmp/test/rustprimer/mysite$ cargo build
   Compiling mysite v0.1.0 (file:///home/vagrant/tmp/test/rustprimer/mysite)
src/main.rs:29:36: 29:52 error: no method named `read_to_string` found for type `iron::request::Body<'_, '_>` in the current scope
src/main.rs:29         let payload = request.body.read_to_string();
                                                  ^~~~~~~~~~~~~~~~
src/main.rs:29:36: 29:52 help: items from traits can only be used if the trait is in scope; the following trait is implemented but not in scope, perhaps add a `use` for it:
src/main.rs:29:36: 29:52 help: candidate #1: use `std::io::Read`
error: aborting due to previous error
Could not compile `mysite`.

編譯出錯了,太糟糕了,提示說沒有read_to_string這個方法,然后我去文檔查了一下,發(fā)現(xiàn)有read_to_string方法 再看提示信息

src/main.rs:29:36: 29:52 help: items from traits can only be used if the trait is in scope; the following trait is implemented but not in scope, perhaps add a `use` for it:
src/main.rs:29:36: 29:52 help: candidate #1: use `std::io::Read`

讓我們添加一個std::io::Read,這個如果操作過文件,你一定知道怎么寫,添加一下,應(yīng)該能過去了,還是繼續(xù)出錯了,看看報(bào)錯

   Compiling mysite v0.1.0 (file:///home/vagrant/tmp/test/rustprimer/mysite)
src/main.rs:30:36: 30:52 error: this function takes 1 parameter but 0 parameters were supplied [E0061]
src/main.rs:30         let payload = request.body.read_to_string();
                                                  ^~~~~~~~~~~~~~~~
src/main.rs:30:36: 30:52 help: run `rustc --explain E0061` to see a detailed explanation
src/main.rs:31:46: 31:53 error: mismatched types:
 expected `&str`,
    found `core::result::Result<usize, std::io::error::Error>`
(expected &-ptr,
    found enum `core::result::Result`) [E0308]
src/main.rs:31         let request: Greeting = json::decode(payload).unwrap();
                                                            ^~~~~~~
src/main.rs:31:46: 31:53 help: run `rustc --explain E0308` to see a detailed explanation
src/main.rs:30:36: 30:52 error: cannot infer an appropriate lifetime for lifetime parameter `'b` due to conflicting requirements [E0495]
src/main.rs:30         let payload = request.body.read_to_string();
                                                  ^~~~~~~~~~~~~~~~
src/main.rs:29:5: 35:6 help: consider using an explicit lifetime parameter as shown: fn set_greeting<'a>(request: &mut Request<'a, 'a>) -> IronResult<Response>
src/main.rs:29     fn set_greeting(request: &mut Request) -> IronResult<Response> {
src/main.rs:30         let payload = request.body.read_to_string();
src/main.rs:31         let request: Greeting = json::decode(payload).unwrap();
src/main.rs:32         let greeting = Greeting { msg: request.msg };
src/main.rs:33         let payload = json::encode(&greeting).unwrap();
src/main.rs:34         Ok(Response::with((status::Ok, payload)))
               ...
error: aborting due to 3 previous errors
Could not compile `mysite`.

第一句提示我們,這個read_to_string(),至少要有一個參數(shù),但是我們一個都沒有提供。 我們看看read_to_string的用法


se std::io;
use std::io::prelude::*;
use std::fs::File;

let mut f = try!(File::open("foo.txt"));
let mut buffer = String::new();

try!(f.read_to_string(&mut buffer));

用法比較簡單,我們修改一下剛剛的函數(shù):

fn set_greeting(request: &mut Request) -> IronResult<Response> {
        let mut payload = String::new();
        request.body.read_to_string(&mut payload);
        let request: Greeting = json::decode(&payload).unwrap();
        let greeting = Greeting { msg: request.msg };
        let payload = json::encode(&greeting).unwrap();
        Ok(Response::with((status::Ok, payload)))
    }

從request中讀取字符串,讀取的結(jié)果存放到payload中,然后就可以進(jìn)行操作了,編譯之后運(yùn)行,使用curl提交一個post數(shù)據(jù)

$curl -X POST -d '{"msg":"Just trust the Rust"}' http://localhost:3000/set
{"msg":"Just trust the Rust"}

iron 基本告一段落 當(dāng)然還有如何使用html模版引擎,那就是直接看文檔就行了。

nickel

當(dāng)然既然是web框架肯定是iron能干的nicke也能干,所以那我們就看看如何做一個hello 和返回一個html 的頁面

同樣我們創(chuàng)建cargo new site --bin,然后添加nickel到cargo.toml中,cargo build


#[macro_use] extern crate nickel;

use nickel::Nickel;

fn main() {
    let mut server = Nickel::new();

    server.utilize(router! {
        get "**" => |_req, _res| {
            "Hello world!"
        }
    });

    server.listen("127.0.0.1:6767");
}

簡單來看,也就是這樣回事。

  1. 引入了nickel的宏
  2. 初始化Nickel
  3. 調(diào)用utilize來定義路由模塊。
  4. router! 宏,傳入的參數(shù)是 get 方法和對應(yīng)的路徑,"**"是全路徑匹配。
  5. listen啟動服務(wù)器

當(dāng)然我們要引入關(guān)于html模版相關(guān)的信息

#[macro_use] extern crate nickel;

use std::collections::HashMap;
use nickel::{Nickel, HttpRouter};

fn main() {
    let mut server = Nickel::new();

    server.get("/", middleware! { |_, response|
        let mut data = HashMap::new();
        data.insert("name", "user");
        return response.render("site/assets/template.tpl", &data);
    });

    server.listen("127.0.0.1:6767");
}

上面的信息你可以編譯,使用curl看看發(fā)現(xiàn)出現(xiàn)

$ curl http://127.0.0.1:6767
Internal Server Error

看看文檔,沒發(fā)現(xiàn)什么問題,我緊緊更換了一個文件夾的名字,這個文件夾我也創(chuàng)建了。 然后我在想難道是服務(wù)器將目錄寫死了嗎?于是將上面的路徑改正這個,問題解決。

return response.render("examples/assets/template.tpl", &data);

我們看一下目錄結(jié)構(gòu)

.
|-- Cargo.lock
|-- Cargo.toml
|-- examples
|   `-- assets
|       `-- template.tpl
|-- src
|   `-- main.rs