设为首页 收藏本站
查看: 978|回复: 0

[经验分享] 代码片段 - Golang 实现简单的 Web 服务器

[复制链接]

尚未签到

发表于 2018-9-20 09:20:18 | 显示全部楼层 |阅读模式
------------------------------  

  
  下面一段代码,实现了最简单的 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 = `
  

  

  
测试
  

  

  

  
用户名:
  

  
请输入文本:
  

  

  

  

  
`
  

  
// 用于将页面重定向到主页
  
var redirectHTML = `
  

  

  

  

  

  
`
  

  
// 处理主页请求
  
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 文件用于存放主页、反馈页面、重定向页面,内容如下:
  

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

  

  

  

  

  
测试
  

  

  

  
用户名:
  

  
请输入文本:
  

  

  

  

  

  

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

  

  

  

  

  

  

  
你好 {{.Name}},你输入的内容是:
  
{{.Text}}
  
返回
  

  

  

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

  

  

  

  

  

  

  

  

  

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

  
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)
  
}
  
}
  

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

  
  上面的例子只是简陋的代码,帮助入门,更深入的内容,请自行学习。
  

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

  

  

  




运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-598652-1-1.html 上篇帖子: 为golang程序使用pprof远程查看httpserver运行堆栈,cpu耗时等信息 下篇帖子: golang数据类型转换
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表