轉(zhuǎn)載請附原文鏈接:http://blog.fandong.me/2017/08/20/iOS-SwiftVaporWeb23/
前言
之前一直有做Java后臺開發(fā)的興趣,可是想到要看好多的Java教程屑那,作為一個iOS開發(fā)者持际,我放棄了,
后來從朋友韓云智VL那里知道了這個框架益眉,竟是用Swift寫的,不得不說郭脂,它燃起了我的興趣澈歉。
Vapor是一個基于Swift開發(fā)的服務(wù)端框架,可以工作于iOS娱颊,Mac OS,Ubuntu箱硕。
為了配合Swift部署到服務(wù)器,我把ECS的服務(wù)器系統(tǒng)改為Ubuntu16.04。
請求體
HTTP.Body
表示的是HTTP.Message
的有效載荷,并用于傳遞底層數(shù)據(jù),在這次練習(xí)中的一些例子是JSON
,HTML
文本或者二進(jìn)制圖像,我們來看一下具體實現(xiàn)
public enum Body {
case data(Bytes)
case chunked((ChunkStream) throws -> Void)
}
數(shù)據(jù)案例
Data Case
是一個目前最常見的Body
中的HTTP.Message
.它只是一個字節(jié)數(shù)組,與這些字節(jié)數(shù)組關(guān)聯(lián)的序列化協(xié)議或類型通常由Content-Type
請求頭定義,我們來看些例子
Application/JSON
如果我們的Content-Type
請求頭包含application/json
,那么底層二級制數(shù)據(jù)表示序列化的JSON
if let contentType = req.headers["Content-Type"], contentType.contains("application/json"), let bytes = req.body.bytes {
let json = try JSON(bytes: bytes)
print("Got JSON: \(json)")
}
Image/PNG
如果我們的Content-Type
包含image/png
,則底層二進(jìn)制數(shù)據(jù)表示編碼的png.
if let contentType = req.headers["Content-Type"], contentType.contains("image/png"), let bytes = req.body.bytes {
try database.save(image: bytes)
}
分塊案例
分塊案例只適用于Vapor的外發(fā)的HTTP.Message
,傳統(tǒng)意義上,響應(yīng)者的角色是在傳遞之前收集整個分塊編碼,我們可以使用它來異步發(fā)送一個正文.
let body: Body = Body.chunked(sender)
return Response(status: .ok, body: body)
我們也可以手動實現(xiàn),也可以使用Vapor的內(nèi)置便利的初始化器來進(jìn)行對請求體進(jìn)行分塊.
return Response(status: .ok) { chunker in
for name in ["joe", "pam", "cheryl"] {
sleep(1)
try chunker.send(name)
}
try chunker.close()
}
確保在分塊離開范圍之前調(diào)用
close()
BodyRepressentable
除了具體的Body
類型,就像在Vapor中常見,我們也廣泛的支持BodyRepresentable
.這意味著我們通常轉(zhuǎn)換的類型的對象可以互換使用,舉個栗子
return Response(body: "Hello, World!")
在上面的例子中,字符串被轉(zhuǎn)換成二進(jìn)制,并且添加到了請求體中
作為練習(xí),最好使用
Hello,World!
Vapor會自動設(shè)置Content-Type
為合適的值
我們來看看它是如何實現(xiàn)的:
public protocol BodyRepresentable {
func makeBody() -> Body
}
自定義
我們也可以在適用的情況下遵照我們自己的類型,假設(shè)我們有一個自定義的數(shù)據(jù)類型,.vpr
讓我們符合我們的VPR
文件類型
extension VPRFile: HTTP.BodyRepresentable {
func makeBody() -> Body {
// collect bytes
return .data(bytes)
}
}
你可能已經(jīng)注意到,協(xié)議拋出,但是我們沒有實現(xiàn),這在Swift中完全有效,如果你曾經(jīng)手動調(diào)用過這個方法,那你將無法拋出.
現(xiàn)在我們可以直接在我們的Responses
中包含我們的VPR
文件.
drop.get("files", ":file-name") { request in
let filename = try request.parameters.extract("file-name") as String
let file = VPRFileManager.fetch(filename)
return Response(status: .ok, headers: ["Content-Type": "file/vpr"], body: file)
}
作為練習(xí),如果我們經(jīng)常重復(fù)這些過程,我們可能會讓VPRFile
直接遵循ResponseRepresentable
extension VPRFile: HTTP.ResponseRepresentable {
func makeResponse() -> Response {
return Response(
status: .ok,
headers: ["Content-Type": "file/vpr"],
body: file
)
}
}
這是我們上面的例子
drop.get("files", ":file-name") { request in
let filename = try request.parameters.extract("file-name") as String
return VPRFileManager.fetch(filename)
}
我們也可以使用類型安全的路由使其更簡潔:
drop.get("files", String.self) { request, filename in
return VPRFileManager.fetch(filename)
}