Go语言系列- http编程和mysql
阅读原文时间:2023年07月08日阅读:1

一、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 = `

`

func SimpleServer(w http.ResponseWriter, request *http.Request) {
io.WriteString(w, "

hello, world

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

{{.Title}}

hello, {{.Name}}

{{.}}

index.html

我的个人网站

hello, Mary

{Mary 我的个人网站 31}

模板示例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")
}
}

main.go

hello world

{{range .}} {{end}}
{{.Name}} {{.Age}}{{.Title}}

index.html

新建测试表

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", "stu01@qq.com")

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", "stu01@qq.com")
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