http編程
1) Go原生支持 http : import ("net/http") 2) Go 的 http 服務性能和 nginx 比較接近 3) 幾行代碼就可以實現一個 web 服務
http 服務端
// 示例代碼: package main import ( "fmt" "net/http" ) func Hello(w http.ResponseWriter, r *http.Request){ fmt.Println("hello world\n") fmt.Fprintf(w,"hello world") // 返回響應 } func main(){ http.HandleFunc("/",Hello) // 路由;第一個參數是路徑,第二個參數是視圖函數 err := http.ListenAndServe("0.0.0.0:8080",nil) // 監聽並等待請求 if err != nil{ fmt.Println("http listened failed") } }
http 客戶端
// 示例代碼: package main import ( "fmt" "net/http" "io/ioutil" ) func main(){ ret,err := http.Get("https://www.baidu.com/") // 向一個服務器發送 GET 請求;返回的數據都在 ret.Body 里面 if err != nil { fmt.Println("get err:",err) return } data,err := ioutil.ReadAll(ret.Body) // 返回的數據都在 ret.Body 里面 if err != nil { fmt.Println("get data err:",err) return } fmt.Printf("Type:%T\n",data) fmt.Println(string(data)) } // 運行結果: [root@NEO example01_http_client]# go run main/main.go Type:[]uint8 <html> <head> <script> location.replace(location.href.replace("https://","http://")); </script> </head> <body> <noscript><meta http-equiv="refresh" content="0;url=http://www.baidu.com/"></noscript> </body> </html> [root@NEO example01_http_client]#
http常見請求方法
1)Get請求 2)Post請求 3)Put請求 4)Delete請求 5)Head請求 -- > 只請求頁面的頭部
發送 HEAD 請求
// 示例代碼: package main import ( "fmt" "net/http" ) var urls = []string{ "http://www.baidu.com", "http://www.google.com", "http://www.taobao.com", } func main(){ for _,v := range urls{ resp,err := http.Head(v) // 發送 Head 請求 if err != nil { fmt.Printf("head %s failed,err:%v\n",v,err) continue } fmt.Printf("head success,status:%v\n",resp.Status) // resp.Status --> 狀態碼 } } // 運行結果: [root@NEO example01_http_head_request]# go run main/main.go head success,status:200 OK head http://www.google.com failed,err:Head http://www.google.com: dial tcp 75.126.2.43:80: connect: connection timed out head success,status:200 OK [root@NEO example01_http_head_request]# // 自定義超時時間 // 示例代碼: package main import ( "fmt" "net/http" "time" "net" ) var urls = []string{ "http://www.baidu.com", "http://www.google.com", "http://www.taobao.com", } func main(){ for _,v := range urls{ c := http.Client{ // 自定義客戶端 Transport: &http.Transport{ Dial: func(network, addr string) (net.Conn, error){ timeout := time.Second * 2 // 自定義超時時間 return net.DialTimeout(network, addr, timeout) }, }, } start := time.Now() resp,err := c.Head(v) // 用自定義的客戶端發送請求 end := time.Now() interval := end.Sub(start) fmt.Println("interval:",interval) //resp,err := http.Head(v) // 發送 Head 請求 if err != nil { fmt.Printf("head %s failed,err:%v\n",v,err) continue } fmt.Printf("head success,status:%v\n",resp.Status) // resp.Status --> 狀態碼 } } // 運行結果: [root@NEO example01_http_head_request]# go run main/main.go interval: 171.062376ms head success,status:200 OK interval: 2.000789206s head http://www.google.com failed,err:Head http://www.google.com: dial tcp 69.63.184.142:80: i/o timeout interval: 749.542763ms head success,status:200 OK [root@NEO example01_http_head_request]#
http 常見狀態碼:
http.StatusContinue = 100 http.StatusOK = 200 http.StatusFound = 302 http.StatusBadRequest = 400 http.StatusUnauthorized = 401 http.StatusForbidden = 403 http.StatusNotFound = 404 http.StatusInternalServerError = 500
表單處理:
// 示例代碼: package main import ( "io" "net/http" ) // 常量 form 是一段 html 代碼 const form = `<html><body><form action="#" method="post" name="bar"> <input type="text" name="in"/> <input type="text" name="in"/> <input type="submit" value="Submit"/> </form></html></body>` func SimpleServer(w http.ResponseWriter, request *http.Request) { // 請求信息都在 request 中 io.WriteString(w, "<h1>hello, world</h1>") // 返回給客戶端一段html代碼 } func FormServer(w http.ResponseWriter, request *http.Request) { w.Header().Set("Content-Type", "text/html") // w.Head().Set(key,val) ---> 設置響應頭 switch request.Method { // request.Method --> 請求方法 case "GET": io.WriteString(w, form) // 把 form 表單返回給客戶端 case "POST": request.ParseForm() // 需要先解析表單 io.WriteString(w, request.Form["in"][0]) // request.Form["in"] 是一個數組 io.WriteString(w, "\n") io.WriteString(w, request.FormValue("in")) // request.FormValue("in") ---> 獲取表單中的值(name重復時,取最近的一個);推薦使用這個 } } func main() { http.HandleFunc("/test1", SimpleServer) http.HandleFunc("/test2", FormServer) if err := http.ListenAndServe(":8088", nil); err != nil { } }
模板操作
1) 替換
main.go 文件內容如下:
// 示例代碼: package main import ( "fmt" "os" "text/template" // 導入 模板 包 ) type Person struct { Name string age string } func main() { t, err := template.ParseFiles("./index.html") // 解析模板文件; t 是模板對象 if err != nil { fmt.Println("parse file err:", err) return } p := Person{Name: "Mary", age: "31"} // 結構體對象首字母大寫的字段可以導入到模板中 if err := t.Execute(os.Stdout, p); err != nil { // t.Execute() --> 執行模板對象,第一個參數表示輸出到終端,第二個參數表示 導入的結構體對象 fmt.Println("There was an error:", err.Error()) } }
index.html 代碼如下:
<html> <head> // 結構體對象沒有的字段不能導入,要不然會報錯,如下 </head> <body> <p>{{.}} </p> // .表示 p 那個對象 <p> hello, {{.Name}}</p> // .Name 表示 p 對象 的Name字段的值 #} // 首字母小寫的字段也不能在模板中渲染 </body> </html>
運行結果:
// 運行結果: [root@NEO main]# go run main.go <html> <head> // 結構體對象沒有的字段不能導入,要不然會報錯,如下 </head> <body> <p>{Mary 31} </p> // .表示 p 那個對象 <p> hello, Mary</p> // .Name 表示 p 對象 的Name字段的值 #} // 首字母小寫的字段也不能在模板中渲染 </body> </html> [root@NEO main]#
2) if 判斷
main.go 文件內容:
// 示例代碼: package main import ( "fmt" "text/template" // 導入 模板 包 "net/http" ) type Person struct { Name string Age int } func RenderTemplate(w http.ResponseWriter, request *http.Request){ t, err := template.ParseFiles("./index.html") // 解析模板文件; t 是模板對象 if err != nil { fmt.Println("parse file err:", err) return } p := Person{Name: "Mary", Age: 31} // 結構體對象首字母大寫的字段可以導入到模板中 if err := t.Execute(w, p); err != nil { // 模板寫入到在 http.ResponseWriter 中,返回給客戶端 fmt.Println("There was an error:", err.Error()) } } func main() { http.HandleFunc("/template",RenderTemplate) if err := http.ListenAndServe(":8080",nil); err != nil { } }
index.html 文件內容:
<html> <head> </head> <body> /* if 語法: {{if ...}} {{else}} {{end}} */ {# gt 表示大於 #} {{if gt .Age 18}} <p>hello oldman,{{.Name}} </p> {{else}} <p>hello young {{.Name}}</p> {{end}} </body> </html>
if常見操作符:
not 非
{{if not .condition}}
{{end}}
and 與
{{if and .condition1 .condition2}}
{{end}}
or 或
{{if or .condition1 .condition2}}
{{end}}
eq 等於
{{if eq .var1 .var2}}
{{end}}
ne 不等於
{{if ne .var1 .var2}}
{{end}}
lt 小於 (less than)
{{if lt .var1 .var2}}
{{end}}
le 小於等於
{{if le .var1 .var2}}
{{end}}
gt 大於
{{if gt .var1 .var2}}
{{end}}
ge 大於等於
{{if ge .var1 .var2}}
{{end}}
模板中with的用法:
{{with .Var}}
{end}}
示例代碼:
<html> <head> </head> <body> {{with .Name}} <!-- 通過這行的 with ,. 就代表 Name ;只有 with 語句中 . 是 Name --> <p>hello, old man, {{.}}</p> {{end}} </body> </html>
模板的循環:
{{range.}}
{{end }}
示例代碼:
<html> <head> </head> <body> <!-- 遍歷 變量--> {{range .}} {{if gt .Age 18}} <p>hello, old man, {{.Name}}</p> {{else}} <p>hello,young man, {{.Name}}</p> {{end}} {{end}} </body> </html>
Mysql
新建測試表
CREATE TABLE person ( user_id int primary key auto_increment, username varchar(260), sex varchar(260), email varchar(260) ); CREATE TABLE place ( country varchar(200), city varchar(200), telcode int );
安裝連接數據庫的第三方包:
go get -u github.com/go-sql-driver/mysql // 安裝 mysql 驅動 go get github.com/jmoiron/sqlx
鏈接mysql:
// 先在 數據庫主機上分配權限,如下: mysql> grant all privileges on gotest.* to 'root'@'172.16.1.%' identified by '123456'; mysql> flush privileges; // 代碼運行服務器內網地址: 172.16.1.122 database, err := sqlx.Open("mysql", "root:123456@tcp(172.16.1.51:3306)/gotest") // 參數說明: // "mysql" ---> 數據庫類型 // root ---> 用戶名 // 123456 ---> 密碼 // tcp ---> 連接協議 // 172.16.1.50 ---> 數據庫主機地址 // 3306 ---> 端口 // gotest ---> 數據庫名稱
go 數據庫的增刪改查
insert操作
r, err := Db.Exec("insert into person(username, sex, email)values(?, ?, ?)", "stu001", "man", "stu01@qq.com") // ? 是占位符
示例代碼:
package main import ( "fmt" _ "github.com/go-sql-driver/mysql" // _ 表示只是把這個庫引進來做初始化,但並不直接引用這個庫 "github.com/jmoiron/sqlx" // sqlx 在 mysql 驅動的層面上又做了封裝,會更好用些 ) type Person struct { UserId int `db:"user_id"` // tag 就是數據庫中的列名 Username string `db:"username"` Sex string `db:"sex"` Email string `db:"email"` } type Place struct { Country string `db:"country"` City string `db:"city"` TelCode int `db:"telcode"` } var Db *sqlx.DB // Db 就代表一個數據庫;Db 這個變量是線程安全的,因為其內部已經內置實現了一個 連接池 func init() { // init() 函數在 main 函數之前自動執行 database, err := sqlx.Open("mysql", "root:123456@tcp(172.16.1.51:3306)/gotest") // database 是一個數據庫實例 if err != nil { fmt.Println("open mysql failed,", err) return } Db = database } func main() { r, err := Db.Exec("insert into person(username, sex, email)values(?, ?, ?)", "stu001", "man", "stu01@qq.com") if err != nil { fmt.Println("exec failed, ", err) return } id, err := r.LastInsertId() // 剛插入的那條記錄的 id if err != nil { fmt.Println("exec failed, ", err) return } fmt.Println("insert succ:", id) }
Select 操作
err := Db.Select(&person, "select user_id, username, sex, email from person where user_id=?", 1)
示例代碼:
package main import ( "fmt" _ "github.com/go-sql-driver/mysql" "github.com/jmoiron/sqlx" ) type Person struct { UserId int `db:"user_id"` Username string `db:"username"` Sex string `db:"sex"` Email string `db:"email"` } type Place struct { Country string `db:"country"` City string `db:"city"` TelCode int `db:"telcode"` } var Db *sqlx.DB func init() { database, err := sqlx.Open("mysql", "root:123456@tcp(172.16.1.51:3306)/gotest") if err != nil { fmt.Println("open mysql failed,", err) return } Db = database } func main() { var person []Person err := Db.Select(&person, "select user_id, username, sex, email from person where user_id=?", 1) // 從數據庫中查詢出來結果會自動填充到 person 這個結構體中 if err != nil { fmt.Println("exec failed, ", err) return } fmt.Println("select succ:", person) } // 運行結果: [root@NEO example02_mysql_select]# go run main/main.go select succ: [{1 stu001 man stu01@qq.com}] [root@NEO example02_mysql_select]#
update操作
_, err := Db.Exec("update person set username=? where user_id=?", "stu0001", 1)
示例代碼:
package main import ( "fmt" _ "github.com/go-sql-driver/mysql" "github.com/jmoiron/sqlx" ) type Person struct { UserId int `db:"user_id"` Username string `db:"username"` Sex string `db:"sex"` Email string `db:"email"` } type Place struct { Country string `db:"country"` City string `db:"city"` TelCode int `db:"telcode"` } var Db *sqlx.DB func init() { database, err := sqlx.Open("mysql", "root:123456@tcp(172.16.1.51:3306)/gotest") if err != nil { fmt.Println("open mysql failed,", err) return } Db = database } func main() { _, err := Db.Exec("update person set username=? where user_id=?", "stu0001", 1) // 更新操作 if err != nil { fmt.Println("exec failed, ", err) return } }
Delete 操作
_, err := Db.Exec("delete from person where user_id=?", 1)
示例代碼:
package main import ( "fmt" _ "github.com/go-sql-driver/mysql" "github.com/jmoiron/sqlx" ) type Person struct { UserId int `db:"user_id"` Username string `db:"username"` Sex string `db:"sex"` Email string `db:"email"` } type Place struct { Country string `db:"country"` City string `db:"city"` TelCode int `db:"telcode"` } var Db *sqlx.DB func init() { database, err := sqlx.Open("mysql", "root:123456@tcp(172.16.1.51:3306)/gotest") if err != nil { fmt.Println("open mysql failed,", err) return } Db = database } func main() { _, err := Db.Exec("delete from person where user_id=?", 1) if err != nil { fmt.Println("exec failed, ", err) return } fmt.Println("delete succ") }