http程式設計
一、Http協定
1. 什麼是協定?
協定,是指通信的雙方,在通信流程或内容格式上,共同遵守的标準。
2. 什麼是http協定?
http協定,是網際網路中最常見的網絡通信标準。
3. http協定的特點
①通信流程:斷開式(無狀态)
斷開式:http協定每次響應完成後,會斷開與用戶端的連接配接
無狀态:由于伺服器斷開了之前的連接配接,就無法知曉連接配接間的關系
②内容格式:消息頭和消息體
二、http程式設計概述
HTTP(HyperText Transfer Protocol,超文本傳輸協定)是網際網路上應用最為廣泛的一種網絡協定,定義了用戶端和服務端之間請求和響應的傳輸标準。Go語言标準庫内建提供了net/http包,涵蓋了HTTP用戶端和服務端的具體實作。使用net/http包,我們可以很友善地編寫HTTP用戶端或服務端的程式。
特點:
- a. Go原生支援http,import(“net/http”)
- b. Go的http服務性能和nginx比較接近
- c. 幾行代碼就可以實作一個web服務
三、用戶端與服務端
1. 服務端
package main
import (
"fmt"
"net/http"
)
//w, 給用戶端回複資料
//r, 讀取用戶端發送的資料
func HandConn(w http.ResponseWriter, r *http.Request) {
fmt.Println("r.Method = ", r.Method)
fmt.Println("r.URL = ", r.URL)
fmt.Println("r.Header = ", r.Header)
fmt.Println("r.Body = ", r.Body)
w.Write([]byte("hello go")) //給用戶端回複資料
}
func main() {
//注冊處理函數,使用者連接配接,自動調用指定的處理函數
http.HandleFunc("/", HandConn)
//監聽綁定
http.ListenAndServe(":8000", nil)
}
package main
import (
"fmt"
"net/http"
)
func Hello(w http.ResponseWriter, r *http.Request) {
fmt.Println("r.Method = ", r.Method)
fmt.Println("r.URL = ", r.URL)
fmt.Println("r.Header = ", r.Header)
fmt.Println("r.Body = ", r.Body)
fmt.Println("handle hello")
fmt.Fprintf(w, "hello ")
}
func login(w http.ResponseWriter, r *http.Request) {
fmt.Println("handle login")
fmt.Fprintf(w, "login ")
}
func history(w http.ResponseWriter, r *http.Request) {
fmt.Println("handle history")
fmt.Fprintf(w, "history ")
}
func main() {
http.HandleFunc("/", Hello)
http.HandleFunc("/user/login", login)
http.HandleFunc("/user/history", history)
err := http.ListenAndServe("0.0.0.0:8880", nil)
if err != nil {
fmt.Println("http listen failed")
}
}
http_server.go
2. 用戶端
package main
import (
"fmt"
"net/http"
)
func main() {
//resp, err := http.Get("http://www.baidu.com")
resp, err := http.Get("http://127.0.0.1:8000")
if err != nil {
fmt.Println("http.Get err = ", err)
return
}
defer resp.Body.Close()
fmt.Println("Status = ", resp.Status)
fmt.Println("StatusCode = ", resp.StatusCode)
fmt.Println("Header = ", resp.Header)
//fmt.Println("Body = ", resp.Body)
buf := make([]byte, 4*1024)
var tmp string
for {
n, err := resp.Body.Read(buf)
if n == 0 {
fmt.Println("read err = ", err)
break
}
tmp += string(buf[:n])
}
//讀取網頁内容,列印出來
fmt.Println("tmp = ", tmp)
}
package main
import (
"fmt"
"io/ioutil"
"net/http"
)
func main() {
res, err := http.Get("https://www.baidu.com/")
if err != nil {
fmt.Println("get err:", err)
return
}
data, err := ioutil.ReadAll(res.Body)
if err != nil {
fmt.Println("get data err:", err)
return
}
fmt.Println(string(data))
}
http_client.go
四、http常見請求方法
HTTP請求的方法:
HTTP/1.1協定中共定義了八種方法(有時也叫“動作”),來表明Request-URL指定的資源不同的操作方式
- 1、OPTIONS
傳回伺服器針對特定資源所支援的HTTP請求方法,也可以利用向web伺服器發送‘*’的請求來測試伺服器的功能性
- 2、HEAD
向伺服器索與GET請求相一緻的響應,隻不過響應體将不會被傳回。這一方法可以再不必傳輸整個響應内容的情況下,就可以擷取包含在響應小消息頭中的元資訊。
- 3、GET
向特定的資源送出請求。它本質就是發送一個請求來取得伺服器上的某一資源。資源通過一組HTTP頭和呈現資料(如HTML文本,或者圖檔或者視訊等)傳回給用戶端。GET請求中,永遠不會包含呈現資料。
- 4、POST
向指定資源送出資料進行處理請求(例如送出表單或者上傳檔案)。資料被包含在請求體中。POST請求可能會導緻新的資源的建立和/或已有資源的修改。 Loadrunner中對應POST請求函數:web_submit_data,web_submit_form
- 5、PUT
向指定資源位置上傳其最新内容
- 6、DELETE
請求伺服器删除Request-URL所辨別的資源
- 7、TRACE
回顯伺服器收到的請求,主要用于測試或診斷
- 8、CONNECT
HTTP/1.1協定中預留給能夠将連接配接改為管道方式的代理伺服器。
注意:
- 1)方法名稱是區分大小寫的,當某個請求所針對的資源不支援對應的請求方法的時候,伺服器應當傳回狀态碼405(Mothod Not Allowed);當伺服器不認識或者不支援對應的請求方法時,應傳回狀态碼501(Not Implemented)。
- 2)HTTP伺服器至少應該實作GET和HEAD/POST方法,其他方法都是可選的,此外除上述方法,特定的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
常見狀态碼
get 和 post差別
差別:
get請求無消息體,隻能攜帶少量資料
post請求有消息體,可以攜帶大量資料
攜帶資料的方式:
get請求将資料放在url位址中
post請求将資料放在消息體中
GET請求請送出的資料放置在HTTP請求協定頭中,而POST送出的資料則放在實體資料中;
GET方式送出的資料最多隻能有1024位元組,而POST則沒有此限制。
五、Head請求
package main
import (
"fmt"
"net/http"
"net"
"time"
)
var url = []string{
"http://www.baidu.com",
"http://google.com",
"http://taobao.com",
}
func main() {
for _, v := range url {
c := http.Client{
Transport: &http.Transport {
Dial:func(network, addr string) (net.Conn, error){
timeout := time.Second*2
return net.DialTimeout(network, addr, timeout)
},
},
}
resp, err := c.Head(v)
if err != nil {
fmt.Printf("head %s failed, err:%v\n", v, err)
continue
}
fmt.Printf("head succ, status:%v\n", resp.Status)
}
}
六、表單及panic處理
package main
import (
"io"
"log"
"net/http"
)
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></body></html>`
func SimpleServer(w http.ResponseWriter, request *http.Request) {
io.WriteString(w, "<h1>hello, world</h1>")
panic("test test")
}
func FormServer(w http.ResponseWriter, request *http.Request) {
w.Header().Set("Content-Type", "text/html")
switch request.Method {
case "GET":
io.WriteString(w, form)
case "POST":
request.ParseForm()
io.WriteString(w, request.Form["in"][1])
io.WriteString(w, "\n")
io.WriteString(w, request.FormValue("in"))
}
}
func main() {
http.HandleFunc("/test1", logPanics(SimpleServer))
http.HandleFunc("/test2", logPanics(FormServer))
if err := http.ListenAndServe(":8088", nil); err != nil {
}
}
func logPanics(handle http.HandlerFunc) http.HandlerFunc {
return func(writer http.ResponseWriter, request *http.Request) {
defer func() {
if x := recover(); x != nil {
log.Printf("[%v] caught panic: %v", request.RemoteAddr, x)
}
}()
handle(writer, request)
}
}
七、模闆
1. 替換 {{.字段名}}
- if 判斷
- if 常見操作
- {{.}}
- {{with .Var}}... {{end}}
2. 循環
{{range.}}... {{end}}
模闆示例1:
package main
import (
"fmt"
"os"
"text/template"
)
type Person struct {
Name string
Title string
age string
}
func main() {
t, err := template.ParseFiles("day10/template/index.html")
if err != nil {
fmt.Println("parse file err:", err)
return
}
p := Person{Name: "Mary", age: "31", Title: "我的個人網站"}
if err := t.Execute(os.Stdout, p); err != nil {
fmt.Println("There was an error:", err.Error())
}
}
main.go
<html>
<head>
<title>{{.Title}}</title>
</head>
<body>
<p> hello, {{.Name}}</p>
<p> {{.}}</p>
</body>
</html>
index.html
<html>
<head>
<title>我的個人網站</title>
</head>
<body>
<p> hello, Mary</p>
<p> {Mary 我的個人網站 31}</p>
</body>
</html>
模闆示例2
package main
import (
"fmt"
"html/template"
"io"
"net/http"
)
var myTemplate *template.Template
type Result struct {
output string
}
func (p *Result) Write(b []byte) (n int, err error) {
fmt.Println("called by template")
p.output += string(b)
return len(b), nil
}
type Person struct {
Name string
Title string
Age int
}
func userInfo(w http.ResponseWriter, r *http.Request) {
fmt.Println("handle hello")
//fmt.Fprintf(w, "hello ")
var arr []Person
p := Person{Name: "Mary001", Age: 10, Title: "我的個人網站"}
p1 := Person{Name: "Mary002", Age: 10, Title: "我的個人網站"}
p2 := Person{Name: "Mary003", Age: 10, Title: "我的個人網站"}
arr = append(arr, p)
arr = append(arr, p1)
arr = append(arr, p2)
resultWriter := &Result{}
io.WriteString(resultWriter, "hello world")
err := myTemplate.Execute(w, arr)
if err != nil {
fmt.Println(err)
}
fmt.Println("template render data:", resultWriter.output)
//myTemplate.Execute(w, p)
//myTemplate.Execute(os.Stdout, p)
//file, err := os.OpenFile("C:/test.log", os.O_CREATE|os.O_WRONLY, 0755)
//if err != nil {
// fmt.Println("open failed err:", err)
// return
//}
}
func initTemplate(filename string) (err error) {
myTemplate, err = template.ParseFiles(filename)
if err != nil {
fmt.Println("parse file err:", err)
return
}
return
}
func main() {
initTemplate("day10/template_http/index.html")
http.HandleFunc("/user/info", userInfo)
err := http.ListenAndServe("0.0.0.0:8880", nil)
if err != nil {
fmt.Println("http listen failed")
}
}
<html>
<head>
</head>
<body>
<p>hello world</p>
<table border="1">
{{range .}}
<tr>
<td>{{.Name}}</td> <td>{{.Age}}</td><td>{{.Title}}</td>
</tr>
{{end}}
</table>
</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
)
1. 連接配接mysql
database, err := sqlx.Open("mysql", "root:@tcp(127.0.0.1:3306)/test")
2. insert操作
r, err := Db.Exec("insert into person(username, sex, email)values(?, ?, ?)", "stu001", "man", "[email protected]")
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:0000@tcp(127.0.0.1:3306)/test")
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", "[email protected]")
if err != nil {
fmt.Println("exec failed, ", err)
return
}
id, err := r.LastInsertId()
if err != nil {
fmt.Println("exec failed, ", err)
return
}
fmt.Println("insert succ:", id)
}
mysql_insert
3. 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:0000@tcp(127.0.0.1:3306)/test")
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)
if err != nil {
fmt.Println("exec failed, ", err)
return
}
fmt.Println("select succ:", person)
}
mysql_select
4. 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:0000@tcp(127.0.0.1:3306)/test")
if err != nil {
fmt.Println("open mysql failed,", err)
return
}
Db = database
}
func main() {
_, err := Db.Exec("update person set username=? where user_id=?", "stu0003", 1)
if err != nil {
fmt.Println("exec failed, ", err)
return
}
}
mysql_update
5. 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:0000@tcp(127.0.0.1:3306)/test")
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")
}
mysql_delete
作者:張亞飛