基于Swift的Web框架Vapor2.0文檔(翻譯)HTTP-Middleware

轉(zhuǎn)載請(qǐng)附原文鏈接:http://blog.fandong.me/2017/08/18/iOS-SwiftVaporWeb22/

前言

之前一直有做Java后臺(tái)開發(fā)的興趣髓抑,可是想到要看好多的Java教程焰扳,作為一個(gè)iOS開發(fā)者,我放棄了使套,
后來從朋友韓云智VL那里知道了這個(gè)框架,竟是用Swift寫的,不得不說罩锐,它燃起了我的興趣。
Vapor是一個(gè)基于Swift開發(fā)的服務(wù)端框架卤唉,可以工作于iOS涩惑,Mac OS,Ubuntu搬味。
為了配合Swift部署到服務(wù)器,我把ECS的服務(wù)器系統(tǒng)改為Ubuntu16.04境氢。

Vapor 2.0 - 文檔目錄
以下文字翻譯自Vapor Docs/HTTP/Middle

中間件

中間件是任何現(xiàn)代Web框架的重要組成部分,它允許你在客戶端和服務(wù)器之間經(jīng)過時(shí)修改請(qǐng)求和響應(yīng).
您可以將中間件看作連接您的服務(wù)器和請(qǐng)求您的網(wǎng)絡(luò)應(yīng)用程序的客戶端的邏輯.

版本中間件

例如,讓我們創(chuàng)建一個(gè)中間件,對(duì)每個(gè)響應(yīng)添加我們的API版本,中間件看起來會(huì)是這樣的:

import HTTP

final class VersionMiddleware: Middleware {
    func respond(to request: Request, chainingTo next: Responder) throws -> Response {
        let response = try next.respond(to: request)

        response.headers["Version"] = "API v1.0"

        return response
    }
}

我們將這個(gè)中間件提供給我們的Droplet容器

import Vapor

let config = try Config()

config.addConfigurable(middleware: VersionMiddleware(), name: "version")

let drop = try Droplet(config)

你現(xiàn)在可以再配置文件中啟用和禁用此中間件,只需要添加version到您的droplet.json中的middleware數(shù)組,請(qǐng)查看配置文件章節(jié)

你可以想見,我們的版本中間件就在連接客戶端和我們的服務(wù)器中間,訪問我們的服務(wù)器每一個(gè)請(qǐng)求和響應(yīng)都必須經(jīng)過這個(gè)中間件鏈.


分解

我們一行一行的分解中間件

let response = try next.respond(to: request)

由于VersionMiddleware在這個(gè)例子中沒有修改請(qǐng)求,所以我們要求下一個(gè)中間件來響應(yīng)該請(qǐng)求,鏈條一直下降到Droplet,然后回到發(fā)送給客戶端的響應(yīng).

response.headers["Version"] = "API v1.0"

然后我們定義一個(gè)包含版本的請(qǐng)求頭的響應(yīng).

return response

返回響應(yīng),并將備份任何剩余的中間件,返回給客戶端.

請(qǐng)求

中間件也可以被修改或與請(qǐng)求交互

func respond(to request: Request, chainingTo next: Responder) throws -> Response {
    guard request.cookies["token"] == "secret" else {
        throw Abort(.badRequest)
    }

    return try next.respond(to: request)
}

這個(gè)中間件將要求該請(qǐng)求的cookie具有一個(gè)token鍵值等于secret或其他的,請(qǐng)求將被終止.

錯(cuò)誤

中間件是捕獲程序中任意位置錯(cuò)誤的完美地方,當(dāng)您讓中間件捕獲錯(cuò)誤時(shí),您可以從路由閉包中刪除大量重復(fù)的邏輯,看看下面的例子:

enum FooError: Error {
    case fooServiceUnavailable
}

假設(shè)您定義了自定義錯(cuò)誤或您正在使用的的其中一個(gè)APIthrows,拋出的錯(cuò)誤必須被捕獲,否則最終將作為用戶意外的內(nèi)部服務(wù)器錯(cuò)誤(500),最明顯的解決方案就是在路由閉包中捕獲錯(cuò)誤

app.get("foo") { request in
    let foo: Foo
    do {
        foo = try getFooFromService()
    } catch {
        throw Abort(.badRequest)
    }

    // continue with Foo object
}

這個(gè)解決方案是有效的,但是如果有多個(gè)路由需要處理這個(gè)錯(cuò)誤,他將會(huì)產(chǎn)生重復(fù)代碼,幸運(yùn)的是,這個(gè)錯(cuò)誤可以在中間件中捕獲

final class FooErrorMiddleware: Middleware {
    func respond(to request: Request, chainingTo next: Responder) throws -> Response {
        do {
            return try next.respond(to: request)
        } catch FooError.fooServiceUnavailable {
            throw Abort(
                .badRequest,
                reason: "Sorry, we were unable to query the Foo service."
            )
        }
    }
}

我們只需要添加這個(gè)中間件到我們的Droplet的配置文件中.

config.addConfigurable(middleware: FooErrorMiddleware(), name: "foo-error")

提示
不要忘記在droplet.json文件中啟用中間件

現(xiàn)在我們的路由閉包看起來好多了,我們也不必?fù)?dān)心代碼的重復(fù)了

app.get("foo") { request in
    let foo = try getFooFromService()

    // continue with Foo object
}

路由組

更細(xì)致的來說,中間件可以應(yīng)用于特定的路由組.

let authed = drop.grouped(AuthMiddleware())
authed.get("secure") { req in
    return Secrets.all().makeJSON()
}

添加到authed組的任何內(nèi)容都必須通過AuthMiddleware.因此,我們可以假定所有訪問/secure的流量已經(jīng)被授權(quán)了,了解更多請(qǐng)查看路由

配置

你可以使用配置文件來啟用或禁用中間件,如果你有中間件,例如,僅在生產(chǎn)環(huán)境中運(yùn)行,這將非常有用.
添加可配置的中間件,像下面這樣

let config = try Config()

config.addConfigurable(middleware: myMiddleware, name: "my-middleware")

let drop = Droplet(config)

然后,在Config/droplet.json文件中,添加my-middlewaremiddleware數(shù)組中.

{
    ...
    "middleware": {
        ...
        "my-middleware",
        ...
    },
    ...
}

如果添加的中間件的名稱出現(xiàn)在中間件陣列中,那么當(dāng)應(yīng)用程序啟動(dòng)時(shí),它將被添加到服務(wù)器的中間件.
按照中間件中的順序

手動(dòng)

如果你不想使用配置文件,你也可以對(duì)中間件進(jìn)行硬編碼.

import Vapor

let versionMiddleware = VersionMiddleware()
let drop = try Droplet(middleware: [versionMiddleware])

高級(jí)

擴(kuò)展

中間件需要與請(qǐng)求/響應(yīng)的擴(kuò)展和存儲(chǔ)有很好的配對(duì)關(guān)系,這個(gè)例子給你還在那時(shí)了如何根據(jù)客戶端的類型為模型動(dòng)態(tài)的返回HTML或JSON響應(yīng)

中間件
final class PokemonMiddleware: Middleware {
    let view: ViewProtocol
    init(_ view: ViewProtocol) {
        self.view = view
    }

    func respond(to request: Request, chainingTo next: Responder) throws -> Response {
        let response = try next.respond(to: request)

        if let pokemon = response.pokemon {
            if request.accept.prefers("html") {
                response.view = try view.make("pokemon.mustache", pokemon)
            } else {
                response.json = try pokemon.makeJSON()
            }
        }

        return response
    }
}

extension PokemonMiddleware: ConfigInitializable {
    convenience init(config: Config) throws {
        let view = try config.resolveView()
        self.init(view)
    }
}
響應(yīng)

延伸到Response.

extension Response {
    var pokemon: Pokemon? {
        get { return storage["pokemon"] as? Pokemon }
        set { storage["pokemon"] = newValue }
    }
}

在這個(gè)例子中,我們給響應(yīng)添加一個(gè)新的屬性來持有一個(gè)口袋對(duì)象,如果中間件發(fā)現(xiàn)了一個(gè)包含口袋對(duì)象的響應(yīng),它將動(dòng)態(tài)的檢查客戶端是否是支持HTML的,如果客戶端是一個(gè)像Safari的瀏覽器,支持HTML,它將會(huì)發(fā)揮一個(gè)Mustache視圖,,如果客戶端不支持HTML,它將會(huì)返回JSON

使用方法

你的閉包現(xiàn)在應(yīng)該看起來這樣


import Vapor

let config = try Config()
config.addConfigurable(middleware: PokemonMiddleware.init, name: "pokemon")

let drop = try Droplet(config)

drop.get("pokemon", Pokemon.self) { request, pokemon in
    let response = Response()
    response.pokemon = pokemon
    return response
}

提示
別忘記添加pokemon到你的droplet.json的中間件數(shù)組

Response Representable

如果你想更進(jìn)一步,你可以使Pokemon遵循ResponseRepresentable

import HTTP

extension Pokemon: ResponseRepresentable {
    func makeResponse() throws -> Response {
        let response = Response()
        response.pokemon = self
        return response
    }
}

現(xiàn)在你的閉包就大大簡化了

drop.get("pokemon", Pokemon.self) { request, pokemon in
    return pokemon
}

中間件是非常強(qiáng)大的.結(jié)合擴(kuò)展,它允許您添加對(duì)框架本身的功能.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市碰纬,隨后出現(xiàn)的幾起案子萍聊,更是在濱河造成了極大的恐慌,老刑警劉巖悦析,帶你破解...
    沈念sama閱讀 217,542評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件寿桨,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡强戴,警方通過查閱死者的電腦和手機(jī)亭螟,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來骑歹,“玉大人预烙,你說我怎么就攤上這事〉烂模” “怎么了扁掸?”我有些...
    開封第一講書人閱讀 163,912評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長最域。 經(jīng)常有香客問我谴分,道長,這世上最難降的妖魔是什么镀脂? 我笑而不...
    開封第一講書人閱讀 58,449評(píng)論 1 293
  • 正文 為了忘掉前任牺蹄,我火速辦了婚禮,結(jié)果婚禮上薄翅,老公的妹妹穿的比我還像新娘沙兰。我一直安慰自己,他們只是感情好翘魄,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,500評(píng)論 6 392
  • 文/花漫 我一把揭開白布鼎天。 她就那樣靜靜地躺著,像睡著了一般熟丸。 火紅的嫁衣襯著肌膚如雪训措。 梳的紋絲不亂的頭發(fā)上伪节,一...
    開封第一講書人閱讀 51,370評(píng)論 1 302
  • 那天光羞,我揣著相機(jī)與錄音绩鸣,去河邊找鬼。 笑死纱兑,一個(gè)胖子當(dāng)著我的面吹牛呀闻,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播潜慎,決...
    沈念sama閱讀 40,193評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼捡多,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了铐炫?” 一聲冷哼從身側(cè)響起垒手,我...
    開封第一講書人閱讀 39,074評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎倒信,沒想到半個(gè)月后科贬,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,505評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡鳖悠,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,722評(píng)論 3 335
  • 正文 我和宋清朗相戀三年榜掌,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片乘综。...
    茶點(diǎn)故事閱讀 39,841評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡憎账,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出卡辰,到底是詐尸還是另有隱情胞皱,我是刑警寧澤,帶...
    沈念sama閱讀 35,569評(píng)論 5 345
  • 正文 年R本政府宣布看政,位于F島的核電站朴恳,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏允蚣。R本人自食惡果不足惜于颖,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,168評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望嚷兔。 院中可真熱鬧森渐,春花似錦、人聲如沸冒晰。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽壶运。三九已至耐齐,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背埠况。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評(píng)論 1 269
  • 我被黑心中介騙來泰國打工耸携, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人辕翰。 一個(gè)月前我還...
    沈念sama閱讀 47,962評(píng)論 2 370
  • 正文 我出身青樓夺衍,卻偏偏與公主長得像,于是被迫代替她去往敵國和親喜命。 傳聞我的和親對(duì)象是個(gè)殘疾皇子沟沙,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,781評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容