通向Golang的捷径【20. 使用 Go 语言的 GAE】
20.1 GAE 介紹
GAE 即為谷歌 App 引擎 (Google App Engine), 是一種云計(jì)算的解決方案, 它可執(zhí)行用戶的 web 應(yīng)用, 并將用戶數(shù)據(jù)保存到 Google 架設(shè)的大量設(shè)備中, 而無須考慮服務(wù)器, 網(wǎng)絡(luò)連接, 操作系統(tǒng)和數(shù)據(jù)存儲等問題, 云端通常會被視為一個(gè)資源集合, 但它的維護(hù)只會交由 Google 來完成, 因此你只需開發(fā)自己的應(yīng)用, 云端會將你的應(yīng)用發(fā)送給用戶, 并會在連接到網(wǎng)絡(luò)的某臺設(shè)備上, 運(yùn)行你的應(yīng)用, 同時(shí)你的軟件只需支付一些資源使用費(fèi)(比如 CPU 的處理時(shí)間, 網(wǎng)絡(luò)帶寬, 磁盤用量, 內(nèi)存用量等), 當(dāng)出現(xiàn)瞬間峰值時(shí), 云平臺可自動為應(yīng)用程序增加資源, 當(dāng)附加的資源不再需要時(shí), 可減少附加的資源, 因此伸縮性是云計(jì)算的優(yōu)勢之一, 協(xié)同應(yīng)用 (多人創(chuàng)建的不同應(yīng)用需一起運(yùn)行, 不同應(yīng)用之間需共享數(shù)據(jù)以及通訊), 可向用戶提供服務(wù)的應(yīng)用, 以及執(zhí)行大量計(jì)算的應(yīng)用, 應(yīng)當(dāng)優(yōu)先選擇云計(jì)算平臺, 同時(shí)云端應(yīng)用的典型用戶接口, 即為瀏覽器.
CAE 發(fā)布于 2008 年, 并支持 Python 應(yīng)用,2009 年增加了 Java 應(yīng)用的支持,2011 年增加了 Go 應(yīng)用的支持,它的官方主頁為 http://code.google.com/appengine/.
GAE 為構(gòu)建和部署 web 應(yīng)用, 提供了一種可靠的具有伸縮性的簡單方式, 保守估計(jì)有一百萬個(gè)應(yīng)用被保存在appspot.com 站點(diǎn)上 (每個(gè)應(yīng)用都有自己的特定域名), 它們都在使用 App 引擎, 這是一種服務(wù)平臺環(huán)境, 它比云架構(gòu) (比如 Amazon EC2) 更高級, 可實(shí)現(xiàn)資源共享的最高效率.
Sandbox
如果你的應(yīng)用運(yùn)行在一個(gè)安全環(huán)境 Sandbox 中, 它可限制來自于底層操作系統(tǒng)的訪問, 同時(shí)允許 App 引擎將web 請求在多個(gè)服務(wù)器之間進(jìn)行分發(fā), 而起始服務(wù)器和終點(diǎn)服務(wù)器需要滿足一些傳輸要求.sandbox 可將你的應(yīng)用, 封閉在一個(gè)安裝可靠的環(huán)境中, 同時(shí)它與硬件, 操作系統(tǒng)以及 web 服務(wù)器的位置無關(guān), 當(dāng)然也存在以下限制:
? web 應(yīng)用不能將數(shù)據(jù), 寫入服務(wù)器的文件系統(tǒng), 同時(shí)應(yīng)用只能讀取更新文件, 應(yīng)用必須使用 App 引擎的
數(shù)據(jù)集, 內(nèi)存緩沖或其他服務(wù), 來處理請求中包含的所有數(shù)據(jù).
? 運(yùn)行代碼只能為一個(gè) web 請求, 或是一個(gè)隊(duì)列任務(wù), 又或是一個(gè)調(diào)度任務(wù), 提供所需的響應(yīng), 同時(shí)響應(yīng)必須在 60s 內(nèi)產(chǎn)生, 一個(gè)請求處理器不能產(chǎn)生一個(gè)子進(jìn)程, 或是在響應(yīng)發(fā)送后, 依然在執(zhí)行.
? 基于網(wǎng)絡(luò)連接, 應(yīng)用只能通過 URL 地址或是郵件服務(wù), 實(shí)現(xiàn)其他 PC 機(jī)的訪問, 而其他 PC 機(jī)也只能通
過標(biāo)準(zhǔn)端口的 HTTP(或 HTTPS) 請求, 與 web 應(yīng)用進(jìn)行交互.
web 應(yīng)用可使用的服務(wù)
? 基于 Google 提供的 Bigtable, 數(shù)據(jù)可保存在 GAE 的數(shù)據(jù)集中, 這是一個(gè)分布式的數(shù)據(jù)存儲服務(wù), 它可
提供一個(gè)查詢引擎和傳輸功能, 并能隨著數(shù)據(jù)的增加, 而使存儲區(qū)自動增加, 所以它并不是一個(gè)傳統(tǒng)的關(guān)
系數(shù)據(jù)庫, 在經(jīng)典 SQL 數(shù)據(jù)庫中, 上述的添加方式不被允許, 但是 GAE 提供了一種類 SQL 的查詢語言
GQL, 其中的數(shù)據(jù)對象被稱為 entity(實(shí)體), 它可包含一個(gè)類型和一組屬性, 基于一個(gè)特定的種類, 可查詢和獲取數(shù)據(jù)庫的實(shí)體, 同時(shí)也可保存實(shí)體的屬性, 同時(shí)實(shí)體的屬性值也應(yīng)當(dāng)符合所支持的數(shù)值類型, 實(shí)體可進(jìn)行編組, 編組可視為傳輸任務(wù)的一個(gè)單元, 因此一次傳輸中必須包含一個(gè)實(shí)體編組, 所以在應(yīng)用中,無須給出數(shù)據(jù)庫的處理, 但是必須提供實(shí)體所包含的所有數(shù)據(jù), 同時(shí)可使用優(yōu)化的并發(fā)控制進(jìn)行更新, 以便獲得最新的數(shù)據(jù)更新.
? 使用集成的 Google Account, 可為 app 進(jìn)行用戶驗(yàn)證.
? URL 獲取功能, 使用該服務(wù), 可使 app 可訪問互聯(lián)網(wǎng)資源, 比如 web 或其他數(shù)據(jù).
? app 可使用內(nèi)建的郵件服務(wù).
? memcache(內(nèi)存緩存) 是一種高性能的內(nèi)存緩沖 (使用鍵值對), 適合于短期使用且無須保存到數(shù)據(jù)集的
數(shù)據(jù), 比如臨時(shí)數(shù)據(jù), 或是來自于數(shù)據(jù)集的數(shù)據(jù)副本 (以實(shí)現(xiàn)高速訪問).
? 圖片的維護(hù)功能
? 任務(wù)調(diào)度和任務(wù)隊(duì)列: 除了響應(yīng) web 請求之外,app 還可執(zhí)行其他任務(wù), 并能在一個(gè)配置好的調(diào)度規(guī)則中,運(yùn)行不同的任務(wù), 比如每天的調(diào)度或每小時(shí)的調(diào)度, 也可選擇將任務(wù), 添加到應(yīng)用的隊(duì)列中, 比如處理請求的后臺任務(wù).
20.2 Go 云處理
在 2010 年 5 月 10 日的 Google I/O 大會上, 發(fā)布了支持 Go 語言的 GAE 版本, 這是一個(gè)實(shí)驗(yàn)版本, 只提供給已注冊的測試者, 而第一個(gè)正式版本發(fā)布于 2011 年 7 月 21 日, 在本書的編寫時(shí)間 (2012 年 1 月) 下,Go App引擎 SDK 的最新版本為 1.6.1(發(fā)布于 20111-12-13), 它支持 Linux 和 Mac OS X(10.5 或更高版本) 系統(tǒng), 并同時(shí)支持 32bit 和 64bit 系統(tǒng), 所使用的 Go 工具鏈版本為 r60.3, 其中給出的一些修改, 無法完全實(shí)現(xiàn)向后兼容,SDK API 的版本為 3.
在 App 引擎中運(yùn)行的 Go app, 可使用 64bit x86 編譯器 (6g) 進(jìn)行編譯, 由于樣機(jī)中只能運(yùn)行一個(gè)線程, 因此所有的并發(fā)協(xié)程將運(yùn)行在一個(gè)操作系統(tǒng)的線程中, 所以面對客戶端請求不會出現(xiàn) CPU 的并行.
Go 語言是 App 引擎支持的首個(gè)可編譯語言, 與其他兩種語言相比,Go 具備一些優(yōu)勢, 如下:
? 與 Java 相比: Go 具有更快的啟動時(shí)間, 以及更好的并發(fā)性能
? 與 Python 相比: Go 具有更好的執(zhí)行性能
20.3 安裝 GAE SDK
20.3.1 安裝
在 Google App Engine 官網(wǎng) (http://code.google.com/appengine/downloads.html) 上, 找到與目標(biāo)平臺相符的GAE SDK 壓縮 (zip) 安裝包. 如果目標(biāo)平臺為 Ubuntu11.10(64bit Linux), 可下載go_appengine_sdk_linux_amd64-1.6.1.zip. 在所需的目錄下 (比如 home 目錄), 解壓該文件, 其中將包含一個(gè)目錄google_appengine, 它包含了 Go 開發(fā)環(huán)境所需的完整 App Engine.
在google_appengine 目錄下, 包含了開發(fā), 構(gòu)建和測試本地 app 的所有工具, 其中將給出一個(gè)AppEngine服務(wù)器 (可用于測試), 同時(shí)還包含了一個(gè)數(shù)據(jù)集, 可用于數(shù)據(jù)存儲, 也就是在云端的AppEngine服務(wù)器上, app的執(zhí)行也需要進(jìn)行數(shù)據(jù)存儲, 同時(shí)其他 API 和工具允許你模擬一個(gè) AppEngine, 以實(shí)現(xiàn) app 的開發(fā)和測試, 在支持 Go 語言的 AppEngine 環(huán)境中, 也包含了 Go 語言的編譯器, 包和附帶工具.
GAE-Go 與 Go 的區(qū)別
在 GAE-Go 中包含了完整的 Go 系統(tǒng), 幾乎所有的標(biāo)準(zhǔn)庫, 因此只有少數(shù)任務(wù), 無法在 AppEngine 環(huán)境中實(shí)現(xiàn), 如下:
? 只包含穩(wěn)定包, 同時(shí) syscall 包已被剔除
? 不支持 cgo(與 c 庫的交互功能), 在 GAE 項(xiàng)目中, 無法使用二進(jìn)制庫 (Go 語言或其他語言), 因此 GAE
項(xiàng)目需要編譯和鏈接所有源碼
? 不支持 go install
? CAE 的發(fā)布時(shí)間通常慢于 Go 語言
另外 Sandbox 環(huán)境 (參見 20.1 節(jié)) 的限制必須考慮, 否則打開一個(gè) socket 或是寫入文件時(shí), 將返回一個(gè)
os.EINVAL 錯(cuò)誤. 同時(shí) GAE-Go 和 Go 的附帶工具是彼此獨(dú)立的, 如果只需在 GAE 中進(jìn)行開發(fā), 則不要
使用 Go 的附帶工具.
在google_appengine 目錄下, 還包含了少量的 Python 腳本, 它將完成 GAE 所需的基本任務(wù), 首先需確認(rèn)這些腳本可以執(zhí)行 (如果無法執(zhí)行, 可使用命令chmod +x *.py), 同時(shí)需將該目錄加入到 PATH 環(huán)境變量中, 以便在調(diào)用這些腳本時(shí), 無須指定它們的路徑, 比如 bash shell, 可在.bashrc 或.profile 文件中, 加入以下命令:
其他細(xì)節(jié)
? 如果已配置了一個(gè)可工作的 Go 環(huán)境,AppEngine 應(yīng)實(shí)現(xiàn)獨(dú)立安裝, 也就是與 Go 環(huán)境互不影響, 尤其是在操作系統(tǒng)中, 不要修改 Go 開發(fā)環(huán)境,GAE-Go 有自己的獨(dú)立環(huán)境, 它的目標(biāo)路徑為 ~/google_appengine/goroot
? 應(yīng)當(dāng)下載 GAE 的文檔, 可在官網(wǎng)中, 下載 google-appengine-docs-20111011.zip 文件并解壓
? 在 GAE 中, 大量使用 Python 語言, 同時(shí) Mac OS X 和 Linux 系統(tǒng)已默認(rèn)安裝了 Python 環(huán)境, 如果未
安裝 Python, 可在官網(wǎng)頁面www.python.org, 下載 Python 2.5
? CAE-Go 的庫和 SDK 也是開源軟件, 可在頁面http://code.google.com/p/appengine-go/中找到, 并可使用命令hg clone https://code.google.com/p/appengine-go/下載
? app 包含的所有 Go 包, 將構(gòu)建成一個(gè)獨(dú)立的可執(zhí)行文件,Go 程序可將需處理的請求派發(fā)給該文件, 這與Java SDK 和 Python SDK 的工作機(jī)制并不相同
在 20.8 節(jié)中, 將看到 CAE 云端如何與 web 應(yīng)用進(jìn)行連接, 在執(zhí)行這一步驟之前, 需要在本地 GAE 環(huán)境中,實(shí)現(xiàn) app 的開發(fā), 測試和運(yùn)行, 同時(shí)本地 GAE 環(huán)境可模擬云端環(huán)境.
20.3.2 檢查與測試
安裝檢查
為保證 google_appengine 目錄中包含的 Go 環(huán)境, 能夠正常工作, 可利用 dev_appserver.py 腳本, 啟動本地的 AppEngine 服務(wù)器, 如果看到以下輸出信息:
則表示一切正常.
運(yùn)行 app demo
在 SDK 中包含了一些 app demo, 調(diào)用這些 demo, 可了解當(dāng)前的 GAE 開發(fā)環(huán)境是否正常.
? 進(jìn)入google_appengine/demos 目錄, 可看到一些文件夾, 比如 helloworld,guestbook 等.
? 進(jìn)入上述的 demo 目錄, 并執(zhí)行命令dev_appserver.py helloworld, 這將導(dǎo)致 Go 程序的自動編譯, 自動鏈接和自動運(yùn)行.
? 上述命令可給出一些警告和輸出信息, 如果在 8080 端口上, 執(zhí)行 helloworld 應(yīng)用, 可使用http://localhost:8080, 之后 helloworld 應(yīng)用將運(yùn)行在本地 AppEngine 服務(wù)器中, 并能為 8080 端口的用戶請求, 提供對應(yīng)的服務(wù).
? 打開瀏覽器, 并輸入http://localhost:8080 地址, 可顯示一個(gè)網(wǎng)頁, 頁面內(nèi)容為:
這時(shí) web 應(yīng)用已成功運(yùn)行在本地 AppEngine 服務(wù)器中. 以下是 helloworld 應(yīng)用的源碼,
例 20.1 helloworld.go
以上的 web 應(yīng)用很簡單 (參見第 15 章), 并在 init 函數(shù)中, 啟動了所有的處理器函數(shù), 同時(shí)在處理器函數(shù)
(handle) 中, 包含了所需的網(wǎng)頁.
20.4 自定義 app(helloworld)
以下將構(gòu)建與上一節(jié) helloworld demo 相同的一個(gè) web 應(yīng)用.
20.4.1 創(chuàng)建一個(gè)簡單的 http 處理器
為自定義 app 創(chuàng)建一個(gè)目錄, 并命名為 helloapp, 該 app 包含的所有文件都放入該目錄中, 在 helloapp 目錄中, 創(chuàng)建另一個(gè)目錄 hello, 其中將包含 Go 源碼 (實(shí)現(xiàn) hello 包), 在 hello 目錄中, 創(chuàng)建一個(gè)文件helloworld2.go, 并在文件中包含以下代碼 (以下代碼與上一節(jié)的 app demo 基本相同),
例 20.2 helloworld2_version1.go
注意包名 hello, 在編寫單獨(dú)的 Go 程序時(shí), 需要在源碼中放入一個(gè) main 包, 但在 GAE-Go 環(huán)境中, 運(yùn)行時(shí)管理將為 web 應(yīng)用, 提供一個(gè) main 包和 http 監(jiān)聽器, 因此可將代碼放入一個(gè)選定的包中, 這里是 hello 包, 其次, 在 AppEngine 上運(yùn)行的 web 應(yīng)用 (Go 語言), 可通過 web 服務(wù)器, 實(shí)現(xiàn)與外部世界的通訊, 這與獨(dú)立的web 應(yīng)用 (Go 語言) 很相似 (參見第 15 章), 所以需要導(dǎo)入 http 包, 并為不同的 url 地址, 定義不同的處理器函數(shù), 同時(shí)不會包含 main 函數(shù), 因此處理器的配置將移入 init 函數(shù), 而 web 服務(wù)器的啟動將由 GAE 完成, 所以 hello 包可響應(yīng)任意請求, 并能回傳一個(gè)包含 Hello, world! 消息的影響.
20.4.2 創(chuàng)建配置文件 app.yaml
所有的 GAE app 都需要提供一個(gè) yaml 配置文件 app.yaml, 它將包含可提供給 GAE 的 app 元數(shù)據(jù) (yaml是一種文本文件的格式, 常用于開源項(xiàng)目, 如果需要深入了解, 可參考網(wǎng)頁www.yaml.org), 該文件可告知 AppEngine, 如何實(shí)現(xiàn)運(yùn)行時(shí)管理, 以及當(dāng)前 web 應(yīng)用可處理那些 URL 地址, 同時(shí)還將為 app demo 保存一個(gè)app.yaml 副本, 并會放置在 helloapp 目錄中.
以下將給出當(dāng)前 app 的文件結(jié)構(gòu):
只有 app.yaml 是一個(gè)必須使用的名稱, 而目錄名,Go 文件名和包名可使用不同的名稱, 但為了便于使用, 上述名稱應(yīng)使用相同或類似的命令, 同時(shí)應(yīng)用的頂層目錄 (helloapp) 應(yīng)包含 app 后綴.
app.yaml 文件能被 AppEngine 讀取和解析, 并能在以下情況中, 執(zhí)行 web 應(yīng)用.
app.yaml 文件可使用 #, 標(biāo)記一個(gè)注釋, 并能在文件中, 包含以下內(nèi)容:
? application: 可給出 web 應(yīng)用的名稱, 這里是 helloworld, 在開發(fā)過程中, 可給出任意名稱, 該名稱將在
AppEngine 中注冊 web 應(yīng)用, 因此需選擇一個(gè)唯一的名稱, 同時(shí)該名稱也接受更新.
? version: 可指定 app 的版本, 事實(shí)上 GAE 可并發(fā)運(yùn)行同一個(gè) app 的不同版本, 但其中一個(gè)版本需指定
為默認(rèn)應(yīng)用, 它可使用字母, 數(shù)字和連號符 (-), 因此可將 T2-31 視為一個(gè)測試版本號, 并將 P2-1 視為一
個(gè)產(chǎn)品版本號.
? runtime: 可標(biāo)記 app 的開發(fā)語言 (可使用 Java 和 Python), 如果需要對 app 進(jìn)行版本更新, AppEngine可保存之前的版本, 之后可在管理員控制臺中, 回滾到之前的版本.
? api_version: 指定當(dāng)前 SDK 中 Go API 的版本, 由于存在與之前版本不兼容的可能性, 如果使用之前的
API 版本, 生成了 app 的早期 (開發(fā)) 版本, 雖然 GAE 可運(yùn)行該 app, 但通常會有一個(gè)時(shí)間限制, 所以必
須將 app 更新到新的 API 版本, 使用 gofix 工具可滿足更新要求.
? handlers: 將包含一個(gè)路由表, 它將告知 GAE, 會有那些請求會發(fā)送給服務(wù)器, 每個(gè)輸入請求都需匹配
url 后續(xù)的正則表達(dá)式 (在本地開發(fā)時(shí),http://localhost:8080/的后續(xù)地址將進(jìn)行匹配, 如果在云端運(yùn)行,
http://appname.appspot.com/的后續(xù)地址將進(jìn)行匹配).
如果請求的 url 地址與首個(gè) url 模式相匹配, 對應(yīng)的 script(腳本) 將執(zhí)行, 在當(dāng)前文件中, 所有請求都能與
/.* 正則表達(dá)式相匹配, 因此 Go 程序需處理所有請求, 在 dev_appserver.py 文件中, 已給出了 _go_app
字符串, 但在云端 App Engine 服務(wù)器上, 將被忽略.
在 helloworld demo 的 app.yaml 文件中, 包含了另一個(gè)處理器, 如下:
有些文件 (static_files, 靜態(tài)文件), 比如圖形文件, 無法進(jìn)行修改 (本例為 favicon.ico), 這類文件將放置在另一個(gè) AppEngine 服務(wù)器的公共緩存中, 以便將它們更快地傳遞給用戶, 如果 web 應(yīng)用中包含了大量的圖形文件, 則應(yīng)放置在一個(gè)單獨(dú)的目錄中, 為了便于使用, 可將目錄命名為 static 或 images.
當(dāng)開發(fā) app 時(shí),upload 給出了必須上傳到云端的內(nèi)容, 如果 app 中包含了大量的圖形文件 (images/(.ico.gif|*.jpg)|), 應(yīng)將本地 images 目錄下的所有文件, 都上傳到 AppEngine 服務(wù)器.
在 GAE 運(yùn)行的大多數(shù)應(yīng)用中, 都會使用模板文件, 這些文件可保存在 app 的根目錄, 或是放置在一個(gè)特殊目錄 tmpl 中. 因此一個(gè) GAE 應(yīng)用的通用目錄結(jié)構(gòu), 如下:
在控制臺中, 進(jìn)入 helloapp 目錄, 并輸入以下命令:
上述兩個(gè)命令都可啟動 web 服務(wù)器, 并監(jiān)聽 8080 端口的請求, 在瀏覽器中輸入http://localhost:8080/, 可測試 web 應(yīng)用是否運(yùn)行成功, 之后可在瀏覽器中, 看到輸出結(jié)果Hello, world!. 同時(shí)在服務(wù)器的控制臺中, 可看到以下輸出信息:
其中<-(A) 表示服務(wù)器就緒,<-(B) 表示服務(wù)器已編譯和運(yùn)行了 Go 程序, <-? 表示 app 已接收到請求, 并響應(yīng)了一個(gè) html 頁面.
當(dāng)服務(wù)器終止運(yùn)行, 或是尚未啟動時(shí), 客戶端 (瀏覽器) 給出 http://localhost:8080/請求, 將在瀏覽器 (Firefox)中, 打印出一條消息, 如下:
20.4.3 開發(fā)的迭代過程
在 app 開發(fā)中, 需要對源碼文件進(jìn)行修改, 也就是對源碼進(jìn)行編輯和保存, 當(dāng)完成源碼文件的修改后, 可重新編譯, 并重啟本地 app, 同時(shí)無須使用 dev_appserver.py. 因此可在 web 服務(wù)器運(yùn)行時(shí), 對helloworld2.go 文件進(jìn)行編輯, 也就是修改Hello, world! 字符串, 在瀏覽器中重新輸入http://localhost:8080/, 可看到 helloworld2.go文件的修改結(jié)果, 而上述任務(wù)也可編寫一個(gè) Rails 或 Django 應(yīng)用, 以便自動實(shí)現(xiàn).
為了終止 web 服務(wù)器, 可在控制臺中, 按下 Ctrl+C 組合鍵, 之后在控制臺中, 可看到以下消息:
其中<-(D) 表示 web 服務(wù)器可獲知 app 的修改和重新編譯,<-(E) 表示 web 服務(wù)器已經(jīng)終止運(yùn)行.
20.4.4 GoClipse IDE 的用法
? 使用 Window / Preferences / Go 菜單, 可指向 GAE-Go 的根目錄.
? 使用 Run / External Tools / External Tools Configuration / Program 菜單, 可在對話框中, 點(diǎn)擊 New按鈕, 可創(chuàng)建一個(gè)新的配置文件, 如下:
再使用 Apply / Run 菜單, 可運(yùn)行 app
在 GoClipse IDE 中, 配置一個(gè)外部工具 (可參考頁面 http://code.google.com/p/goclipse/wiki/DeployingToGoogleAppEngineFromEclipse), 可使 app 的開發(fā)更加簡單.
20.5 用戶服務(wù)
GAE 可基于 Google 的大量硬件設(shè)備, 提供一些有價(jià)值的服務(wù), 如 20.1 節(jié)所述,GAE 可提供用戶服務(wù), 因此可在你的 web 應(yīng)用中, 集成 Google 的賬號驗(yàn)證, 基于用戶服務(wù), 需要使用 web 應(yīng)用的用戶, 可使用 Google 賬號, 并登錄到你的 web 應(yīng)用, 因此用戶服務(wù)可簡化 web 應(yīng)用的私有化.
編輯 helloworld2.go 文件, 加入所需的賬號驗(yàn)證服務(wù), 如下
例 20.3 helloworld2_version2.go
在瀏覽器中重新載入之前的頁面, 這時(shí)在你的 web 應(yīng)用中, 將出現(xiàn)一個(gè)鏈接, 并可重定向到 Google 的登錄頁面 (本地版本), 這可用于 web 應(yīng)用的測試, 如果在瀏覽器中任意輸入一個(gè)用戶名,web 應(yīng)用將獲取到一個(gè)偽造的 user.User 數(shù)值 (基于用戶名產(chǎn)生的數(shù)值), 在 AppEngine 中運(yùn)行的 web 應(yīng)用, 可使用戶看到Google 的賬號登錄頁面, 之后如果成功登錄, 將重定向到你的 web 應(yīng)用, 否則將重定向到賬號創(chuàng)建頁面.
用戶 API
為了實(shí)現(xiàn)上述操作, 需要導(dǎo)入 GAE 提供的一些 Go 包, 比如 appengine 和 appengine/user 包, 在處理器(handler) 中, 首先將創(chuàng)建一個(gè)與當(dāng)前請求 r 關(guān)聯(lián)的 Context(上下文) 對象, 如c := appengine.NewContext?, appengine.NewContext 函數(shù)可返回一個(gè)名為 c 的 appengine.Context 對象, 它可被 Go 語言的 AppEngineSDK 的大多數(shù)函數(shù)所使用, 以便與 AppEngine 服務(wù)進(jìn)行通訊, 從這個(gè)上下文對象中, 可檢查用戶是否完成了登錄操作, 即u := user.Current?.
如果登錄成功,user.Current 可返回一個(gè) user.User 指針 (可表示一個(gè)有效用戶), 否則 user.Current 將返回 nil, 如果登錄不成功, 將滿足u == nil 條件, 之后將使用url, err := user.LoginURL(c, r.URL.String()), 使得用戶瀏覽器重定向到 Google 的賬號登錄頁面, 其中的第二個(gè)參數(shù)r.URL.String(), 即為當(dāng)前請求的 url 地址, 當(dāng)成功登錄后,Google 的賬號登錄機(jī)制可產(chǎn)生一個(gè)重定向 (即定向到所請求的 url 地址), 同時(shí)會設(shè)定一個(gè) Location頭, 并返回一個(gè) http 狀態(tài)碼 302(表示所請求的 url 地址已經(jīng)找到).
LoginURL() 函數(shù)可返回一個(gè)錯(cuò)誤碼, 同時(shí)該函數(shù)不太可能出現(xiàn)錯(cuò)誤, 但是在實(shí)際編程中, 推薦檢查該錯(cuò)誤碼, 并顯示檢查結(jié)果, 如下:
當(dāng)用戶登錄后, 可顯示一個(gè)與用戶賬號關(guān)聯(lián)的私有信息, 即fmt.Fprintf(w, ”Hello, %v!”, u), 在這種情況下, fmt.Fprintf函數(shù)可使用 user.User 的 String 方法, 以獲取用戶賬號的字符串, 更多細(xì)節(jié)可參考頁面 http://
code.google.com/appengine/docs/go/users/.
20.6 表單處理
從 15.6 和 15.7 節(jié)可知, 在 web 應(yīng)用中, 經(jīng)常會使用 template(模板) 包, 這也適用于 GAE app, 在以下代碼中, 可允許用戶輸入一段文本, 首先它可顯示一個(gè)游客 (guestbook) 表單 (基于/(根地址) 處理器), 之后該表單將投遞給 sign(登錄) 處理器, 而不是作為文本, 被添加到響應(yīng) html 中, 同時(shí) sign 函數(shù)可調(diào)用r.FormValue, 獲取到表單數(shù)據(jù), 并將數(shù)據(jù)傳遞給 signTemplate.Execute, 同時(shí) signTemplate.Execute 又可將生成的模板, 傳遞給 http.ResponseWriter. 修改 helloworld2.go 文件, 實(shí)現(xiàn)上述功能, 如下:
例 20.4 helloworld2_version3.go
20.7 數(shù)據(jù)存儲集合
web 應(yīng)用需要從來自于用戶的 html 表單中, 收集所需的信息, 通常情況下, 將會預(yù)定義一些固定的信息位置, 以便從表單中獲取或?qū)懭? 而 GAE 則提供了 DataStore(數(shù)據(jù)存儲) 功能, 可將數(shù)據(jù)保存在多個(gè) web 服務(wù)器, 甚至是多個(gè)設(shè)備上, 以此實(shí)現(xiàn)一個(gè)分布式數(shù)據(jù)庫 (非關(guān)系數(shù)據(jù)庫), 所以用戶的下一次請求可傳遞給另一臺 PC機(jī)的 web 服務(wù)器, 但 GAE 組織架構(gòu)將在一個(gè)簡單的 API 中, 細(xì)心操作所有數(shù)據(jù)的分布式處理, 響應(yīng)處理和負(fù)載平衡, 同時(shí)還提供了一個(gè)強(qiáng)大的查詢引擎.
以下將對之前的示例進(jìn)行擴(kuò)展, 首先將創(chuàng)建一個(gè) Greeting 結(jié)構(gòu), 其中包含了作者, 內(nèi)容和時(shí)間等信息, 因此需要保存該結(jié)構(gòu), 所以需為 entity 程序創(chuàng)建一個(gè)匹配的數(shù)據(jù)結(jié)構(gòu) (即處理器能夠操作的對象), 通常是一個(gè)結(jié)構(gòu)類型, 在運(yùn)行的程序中, 放置在內(nèi)存中的結(jié)構(gòu)所包含的數(shù)據(jù), 都來自于 entity 的 DataStore.
程序可接收的 url 地址, 如下
? url 根地址 (/): 可獲取所有已保存的請求, 并通過 template 包, 將其顯示出來, 參見 15.7 節(jié).
? url 地址 (/sign): 將一個(gè)新的請求, 保存到 DataStore 中.
在以下示例中, 還需要導(dǎo)入 appengine/datastore 包,
例 20.5 helloworld2_version4.go
sign 處理器構(gòu)建了一個(gè) Greeting 變量 g, 其中使用表單內(nèi)容進(jìn)行初始化, 之后使用了 datastore.Put() 進(jìn)行存儲,DataStore 內(nèi)部將為每次數(shù)據(jù)存儲, 生成一個(gè)唯一的 key, 為了實(shí)現(xiàn)上述功能, 在 Put 函數(shù)的調(diào)用中, 將使用datastore.NewIncompleteKey(c, ”Greeting”, nil) 作為第 2 個(gè)參數(shù) (該函數(shù)需傳入一個(gè)結(jié)構(gòu)類型名), 第 3 個(gè)參數(shù)即為 Greeting 變量 g 的指針.
datastor 包還提供了一個(gè) Query 類型, 用于 DataStore 的查詢, 在根地址處理器中, 將構(gòu)建一個(gè)查詢變量 q, 其中將使用請求的 Greeting 對象, 并以日期的降序方式, 對 DataStore 進(jìn)行查詢, 查詢結(jié)果限制在 10 個(gè)以內(nèi).
查詢結(jié)果將保存在一個(gè)結(jié)構(gòu)中, 即一個(gè) Greeting 類型的 slice, 之后調(diào)用 q.GetAll(c, &greetings), 將 slice 轉(zhuǎn)存到 greetings 中, 并檢查查詢結(jié)果中是否存在錯(cuò)誤.
當(dāng)上述操作都通過后, 可將查詢結(jié)果的日期數(shù)據(jù), 都合并到一個(gè)模板中,
它可實(shí)現(xiàn)一個(gè) range 結(jié)構(gòu), 參見 15.7.6 節(jié). 再次測試 helloworld2.go 文件的修改, 在兩次請求之間, 關(guān)閉瀏覽器, 這時(shí)你會發(fā)現(xiàn), 依然可看到之前的請求.
清除服務(wù)器的 DataStore
在開發(fā)過程中,web 服務(wù)器將使用一個(gè)本地 DataStore, 對 web 應(yīng)用進(jìn)行測試, 其實(shí)就是一個(gè)臨時(shí)文件, 請求數(shù)據(jù)會一直保留在臨時(shí)文件中,web 服務(wù)器在沒有得到指令的情況下, 不會清除這些文件, 如果在開發(fā)過程中, 需要清空 DataStore 并重新啟動, 可在啟動服務(wù)器時(shí), 加入–clear_datastore 選項(xiàng),
調(diào)試
在 Go 環(huán)境中, 可運(yùn)行 gdb 調(diào)試器 (可參考頁面http://golang.org/doc/debugging_with_gdb.html), 可將 gdb附加到一個(gè)運(yùn)行進(jìn)程中, 在通常情況下, 可使用 dev_appserver.py, 并在 localhost:8080 地址上, 啟動 app, 使用命令 ps ax | grep _go_app, 可查找到 _go_app 的路徑和 PID, 這時(shí)可將 gdb 附加到 _go_app 進(jìn)程, 之后可給出一個(gè) http 請求, 因此 app 的運(yùn)行將遇到, 在代碼中設(shè)置的斷點(diǎn), 如果對 Go 代碼進(jìn)行了修改, 必須重新編譯并執(zhí)行另一個(gè) _go_app 進(jìn)行調(diào)試.
20.8 云端上傳
在上一節(jié)的示例中, 使用了 Google 的賬號驗(yàn)證功能, 它可實(shí)現(xiàn)消息發(fā)送, 顯示其他已離開用戶的信息, 或是在基本功能上實(shí)現(xiàn)更復(fù)雜的功能, 因此需要在云端進(jìn)行開發(fā), 如果你的應(yīng)用需動用大量的資源, 則應(yīng)當(dāng)進(jìn)行調(diào)整,因?yàn)?GAE 處理具有自動化的伸縮性.
首先你需要申請一個(gè) Google 賬號, 比如使用 gmail 郵件地址, 作為你的用戶名, 在頁面www.google.com/accounts可快速申請一個(gè) Google 賬號.
在頁面https://appengine.google.com/出現(xiàn)的 App Engine Administration Console(App Engine 管理員控制臺) 中, 可創(chuàng)建和管理 App Engine web 應(yīng)用.
完成 SMS 驗(yàn)證后, 可獲得 Create an Application(創(chuàng)建 web 應(yīng)用) 頁面, 選擇 application identifier(應(yīng)用標(biāo)識, 它必須是一個(gè)唯一名稱, 在 GAE 包含的所有應(yīng)用中), 比如 ib-tutgae.appspot.com, 加上 http://前綴, 則可變成 web 應(yīng)用的 url 地址, 后續(xù)無法對應(yīng)用標(biāo)識進(jìn)行修改, 因此可在應(yīng)用名中, 加入個(gè)人喜歡, 以生成一個(gè)私有 app, 或是加入公司名稱, 以生成一個(gè)商用 app, 之后可選擇 application title(應(yīng)用標(biāo)題), 這在 app 中可見, 同時(shí)后續(xù)可對標(biāo)題進(jìn)行修改, 比如 Tutorial GAE App, 去除默認(rèn)的 Google 驗(yàn)證功能和高速 Datastore 功能 (Google Authentication,High Replication Datastore), 以便在 GAE 中運(yùn)行 web 應(yīng)用時(shí), 不會產(chǎn)生費(fèi)用問題, 之后點(diǎn)擊 Create Application 按鈕, 將出現(xiàn)一條消息 Application Registered Successfully (應(yīng)用注冊成功), 之后可將 app 應(yīng)用上傳到云端, 如下:
? 編輯 app.yaml 文件, 修改 web 應(yīng)用的數(shù)值, 將 helloworld 變更為 ib-tutgae
? 為了將 web 應(yīng)用上傳到 GAE 并進(jìn)行配置, 可使用 appcfg.py 腳本命令, 即 appcfg.py update helloapp/
當(dāng)你的 Google 賬號驗(yàn)證成功后,web 應(yīng)用將上傳到運(yùn)行, 并能在 App Engine 中開發(fā)了.
如果需要更新 web 應(yīng)用的新版本, 首先需要處理代碼中出現(xiàn)的錯(cuò)誤, 完成 app 的編譯后, 才可將 app 上傳到云端, 否則上傳沒有任何意義, 使用頁面http://application-id.appspot.com, 可在云端上, 對 web 應(yīng)用進(jìn)行測試, 其中 application-id 即為唯一的應(yīng)用標(biāo)識, 這里是http://ib-tutgae.appspot.com, 這類測試同時(shí)支持工作在Windows,Linux,OS X 平臺的瀏覽器.
對 web 應(yīng)用進(jìn)行監(jiān)控
進(jìn)入https://appengine.google.com/頁面, 可給出一個(gè)列表, 其中包含了你的所有應(yīng)用, 點(diǎn)擊某個(gè)應(yīng)用, 將彈出它的控制面板, 其中可提供 web 應(yīng)用的監(jiān)控服務(wù), 如下圖,
監(jiān)控功能是相當(dāng)重要的, 因?yàn)?web 應(yīng)用工作在云端, 這意味著你只能進(jìn)行訪問, 無法掌控代碼運(yùn)行的狀態(tài)或是進(jìn)行調(diào)試, 而從監(jiān)控功能的圖形結(jié)果中可知,web 應(yīng)用的負(fù)載狀況 (每秒的請求數(shù)), 消耗的資源數(shù) (CPU 用量, 帶寬, 存儲用量, 數(shù)據(jù)復(fù)制, 后臺用量), 費(fèi)用產(chǎn)生的明細(xì), 可查看負(fù)載信息, 即每個(gè) url 地址的請求數(shù)和 cpu 負(fù)載, 或是查看錯(cuò)誤信息, 即 web 應(yīng)用出現(xiàn)錯(cuò)誤時(shí), 所給出的信息, 數(shù)據(jù)面板 (Data Panel) 和 Datastore 查看器 (Viewer) 可查看和查詢你的 Datastore 數(shù)據(jù), 使用 Administration 查看方式, 還可得到一些特殊信息, 以及GAE 文檔的鏈接, 選擇 Main/Logs 路徑, 可參看每次請求的日志, 以及錯(cuò)誤異常的日志記錄 (而異常不會顯示給用戶).
總結(jié)
以上是生活随笔為你收集整理的通向Golang的捷径【20. 使用 Go 语言的 GAE】的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: vbs模拟post请求上传文件
- 下一篇: 分布式限速器