代碼片段 - Golang 實現簡單的 Web 服務器


------------------------------   下面一段代碼,實現了最簡單的 Web 服務器: 編譯環境:   Linux Mint 18 Cinnamon 64-bit   Golang 1.7 ------------------------------ // main.go package main import ( "fmt" "log" "net/http" ) // 處理主頁請求 func index(w http.ResponseWriter, r *http.Request) { // 向客戶端寫入內容 fmt.Fprintf(w, "Hello World!") } func main() { http.HandleFunc("/", index) //設置訪問的路由 err := http.ListenAndServe(":9090", nil) //設置監聽的端口 if err != nil { log.Fatal("ListenAndServe: ", err) } } ------------------------------   執行上面的程序之后,打開 Web 瀏覽器,在地址欄輸入:127.0.0.1:9090 就可以訪問這個服務器了。它只實現了最簡單的單一頁面的輸出。   接下來我們讓服務器接受客戶端輸入的數據,然后將其反饋給客戶端。   首先,我們要向客戶端寫入一個表單頁面,以便客戶端有地方可以填寫數據和提交數據。然后還需要在服務端添加一個頁面處理函數,用來處理用戶提交的數據。下面就開始實現這個功能。 ------------------------------ // main.go package main import ( "fmt" "log" "net/http" ) // 向客戶端寫入這些數據,以便客戶端可以填寫文本並提交 var indexHTML = `<html> <head> <meta http-equiv="Content-type" content="text/html; charset=utf-8"> <title>測試</title> </head> <body> <form action="/page" method="post"> 用戶名:<br> <input name="username" type="text"><br> 請輸入文本:<br> <textarea name="usertext"></textarea><br> <input type="submit" value="提交"> </form> </body> </html>` // 用於將頁面重定向到主頁 var redirectHTML = `<html> <head> <meta http-equiv="Content-type" content="text/html; charset=utf-8"> <meta http-equiv="Refresh" content="0; url={{.}}"> </head> <body></body> </html>` // 處理主頁請求 func index(w http.ResponseWriter, r *http.Request) { // 向客戶端寫入我們准備好的頁面 fmt.Fprintf(w, indexHTML) } // 處理客戶端提交的數據 func page(w http.ResponseWriter, r *http.Request) { // 我們規定必須通過 POST 提交數據 if r.Method == "POST" { // 解析客戶端請求的信息 if err := r.ParseForm(); err != nil { log.Println(err) } // 獲取客戶端輸入的內容 userName := r.Form.Get("username") userText := r.Form.Get("usertext") // 將內容反饋給客戶端 fmt.Fprintf(w, "你好 %s,你輸入的內容是:%s", userName, userText) } else { // 如果不是通過 POST 提交的數據,則將頁面重定向到主頁 fmt.Fprintf(w, redirectHTML) } } func main() { http.HandleFunc("/", index) // 設置訪問的路由 http.HandleFunc("/page", page) // 設置訪問的路由 err := http.ListenAndServe(":9090", nil) // 設置監聽的端口 if err != nil { log.Fatal("ListenAndServe: ", err) } } ------------------------------   到此,我們已經實現了客戶端和服務端的自由交互,但是將“頁面內容”和“邏輯代碼”混在一起總是不好的,下我們把“頁面內容”和“邏輯代碼”分開存放。   在 views 目錄中創建 3 個 html 文件用於存放主頁、反饋頁面、重定向頁面,內容如下: ------------------------------ <!-- views/index.html --> <html> <head> <meta http-equiv="Content-type" content="text/html; charset=utf-8"> <title>測試</title> </head> <body> <form action="/page" method="post"> 用戶名:<br> <input name="username" type="text"><br> 請輸入文本:<br> <textarea name="usertext"></textarea><br> <input type="submit" value="提交"> </form> </body> </html> ------------------------------ <!-- views/page.html --> <html> <head> <meta http-equiv="Content-type" content="text/html; charset=utf-8"> </head> <body> <h3>你好 {{.Name}},你輸入的內容是:</h3> <pre>{{.Text}}</pre> <p><a href="/">返回</a></p> </body> </html> ------------------------------ <!-- views/redirect.html --> <html> <head> <meta http-equiv="Content-type" content="text/html; charset=utf-8"> <meta http-equiv="Refresh" content="0; url={{.}}"> </head> <body></body> </html> ------------------------------ main.go 的內容如下: ------------------------------ // main.go package main import ( "html/template" "log" "net/http" ) func checkErr(err error) { if err != nil { log.Println(err) } } // 存放用戶數據 type UserData struct { Name string Text string } // 渲染頁面並輸出 func renderHTML(w http.ResponseWriter, file string, data interface{}) { // 獲取頁面內容 t, err := template.New(file).ParseFiles("views/" + file) checkErr(err) // 將頁面渲染后反饋給客戶端 t.Execute(w, data) } // 處理主頁請求 func index(w http.ResponseWriter, r *http.Request) { // 渲染頁面並輸出 renderHTML(w, "index.html", "no data") } // 處理用戶提交的數據 func page(w http.ResponseWriter, r *http.Request) { // 我們規定必須通過 POST 提交數據 if r.Method == "POST" { // 解析客戶端請求的信息 if err := r.ParseForm(); err != nil { log.Println("Handler:page:ParseForm: ", err) } // 獲取客戶端輸入的內容 u := UserData{} u.Name = r.Form.Get("username") u.Text = r.Form.Get("usertext") // 渲染頁面並輸出 renderHTML(w, "page.html", u) } else { // 如果不是通過 POST 提交的數據,則將頁面重定向到主頁 renderHTML(w, "redirect.html", "/") } } func main() { http.HandleFunc("/", index) // 設置訪問的路由 http.HandleFunc("/page", page) // 設置訪問的路由 err := http.ListenAndServe(":9090", nil) // 設置監聽的端口 if err != nil { log.Fatal("ListenAndServe: ", err) } } ------------------------------   一般在收到客戶端數據后,我們都希望把它存儲在服務器中,以便客戶端隨時可以讀取,下面我們就來實現這個功能,將用戶提交的數據存儲到服務器的 SQLite 數據庫中(SQLite 僅用於測試,實際站點推薦使用 MongoDb)。   當然需要 "github.com/mattn/go-sqlite3" 這個包和 SQLite 開發環境: 1、在 Linux Mint 的終端輸入“go get github.com/mattn/go-sqlite3”獲取包文件。 2、在 Linux Mint 的軟件管理器中搜索“Golang-github-mattn-go-sqlite3-dev”並安裝。 3、在 Linux Mint 的軟件管理器中搜索“SQLiteman”並安裝(可選),用於查看 SQLite 數據庫。   開發環境搭建好后,下面就是數據庫操作代碼: ------------------------------ // main.go package main import ( "database/sql" "html/template" "log" "net/http" _ "github.com/mattn/go-sqlite3" ) func checkErr(err error) { if err != nil { log.Println(err) } } // 存放用戶數據 type UserData struct { Name string Text string } // 渲染頁面並輸出 func renderHTML(w http.ResponseWriter, file string, data interface{}) { // 獲取頁面內容 t, err := template.New(file).ParseFiles("views/" + file) checkErr(err) // 將頁面渲染后反饋給客戶端 t.Execute(w, data) } // 寫入數據庫(返回寫入后的數據) func writeData(userData *UserData) string { // 打開數據庫 db, err := sql.Open("sqlite3", "./data.db") checkErr(err) defer db.Close() // 如果數據表不存在則創建(如果存在則跳過) db.Exec(`create table data (id integer not null primary key, name text, data string);`) var olddata string // 數據庫中已存在的數據 var sqlStmt string // sql 內容 // 查詢用戶是否存在,同時讀取用戶數據 err = db.QueryRow("select data from data where name = ?", userData.Name).Scan(&olddata) if err != nil { // 用戶不存在 sqlStmt = "insert into data(data, name) values(?,?)" // 添加數據 } else { // 用戶存在 sqlStmt = "update data set data = ? where name == ?" // 更新數據 // 如果 data 為空,則刪除用戶 if len(userData.Text) == 0 { sqlStmt = "delete from data where data >= ? and name == ?" // 刪除字段 } else { // 否則將 data 追加到數據庫 userData.Text = olddata + "\n" + userData.Text } } // 准備 SQL stmt, err := db.Prepare(sqlStmt) checkErr(err) defer stmt.Close() // 執行 SQL _, err = stmt.Exec(userData.Text, userData.Name) checkErr(err) return userData.Text } // 處理主頁請求 func index(w http.ResponseWriter, r *http.Request) { // 渲染頁面並輸出 renderHTML(w, "index.html", "no data") } // 處理用戶提交的數據 func page(w http.ResponseWriter, r *http.Request) { // 我們規定必須通過 POST 提交數據 if r.Method == "POST" { // 解析客戶端請求的信息 if err := r.ParseForm(); err != nil { log.Println("Handler:page:ParseForm: ", err) } // 獲取客戶端輸入的內容 u := UserData{} u.Name = r.Form.Get("username") u.Text = r.Form.Get("usertext") // 寫入數據庫,同時獲取處理后的數據 u.Text = writeData(&u) // 渲染頁面並輸出 renderHTML(w, "page.html", u) } else { // 如果不是通過 POST 提交的數據,則將頁面重定向到主頁 renderHTML(w, "redirect.html", "/") } } func main() { http.HandleFunc("/", index) // 設置訪問的路由 http.HandleFunc("/page", page) // 設置訪問的路由 err := http.ListenAndServe(":9090", nil) // 設置監聽的端口 if err != nil { log.Fatal("ListenAndServe: ", err) } } ------------------------------   上面的例子只是簡陋的代碼,幫助入門,更深入的內容,請自行學習。 ------------------------------


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM