天天看點

Go語言系列- http程式設計和mysql

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)
}
      
Go語言系列- http程式設計和mysql
Go語言系列- http程式設計和mysql
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)
}
      
Go語言系列- http程式設計和mysql
Go語言系列- http程式設計和mysql
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伺服器支援擴充自定義的方法。
Go語言系列- http程式設計和mysql
Go語言系列- http程式設計和mysql
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:

Go語言系列- http程式設計和mysql
Go語言系列- http程式設計和mysql
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

Go語言系列- http程式設計和mysql
Go語言系列- http程式設計和mysql
<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      
Go語言系列- http程式設計和mysql
Go語言系列- http程式設計和mysql
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")
    }
}      
Go語言系列- http程式設計和mysql
Go語言系列- http程式設計和mysql
<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]")
      
Go語言系列- http程式設計和mysql
Go語言系列- http程式設計和mysql
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)
      
Go語言系列- http程式設計和mysql
Go語言系列- http程式設計和mysql
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)
      
Go語言系列- http程式設計和mysql
Go語言系列- http程式設計和mysql
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)      
Go語言系列- http程式設計和mysql
Go語言系列- http程式設計和mysql
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

Go語言系列- http程式設計和mysql

作者:張亞飛