代碼片段 - Golang 實現簡單的 Web 服務器 -开发者知识库

代碼片段 - Golang 實現簡單的 Web 服務器 -开发者知识库,第1张

------------------------------

  下面一段代碼,實現了最簡單的 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)
}
}

------------------------------

  上面的例子只是簡陋的代碼,幫助入門,更深入的內容,請自行學習。

------------------------------



最佳答案:

本文经用户投稿或网站收集转载,如有侵权请联系本站。

发表评论

0条回复