您现在的位置是:网站首页> 编程资料编程资料

Go语言中http和mysql的实现代码_Golang_

2023-05-26 334人已围观

简介 Go语言中http和mysql的实现代码_Golang_

http 编程

Go 原生支持http:

import "net/http"

Go 的http服务性能和nginx比较接近:

就是说用Go写的Web程序上线,程序前面不需要再部署nginx的Web服务器,这里省掉的是Web服务器。如果服务器上部署了多个Web应用,还是需要反向代理的,一般这也是nginx或apache。

几行代码就可以实现一个web服务:

 package main import ( "fmt" "net/http" ) func Hello(w http.ResponseWriter, r *http.Request) { fmt.Println(*r) fmt.Fprintf(w, "Hello World") } func main() { http.HandleFunc("/", Hello) err := http.ListenAndServe("0.0.0.0:8000", nil) if err != nil { fmt.Println("http Listen failed") } }

http client

http 常见的请求方法:

  • Get请求
  • Post请求
  • Put请求
  • Delete请求
  • Head请求

Get 请求

使用Get请求网站的示例:

 package main import ( "fmt" "io/ioutil" "net/http" ) func main() { res, err := http.Get("http://edu.51cto.com") if err != nil { fmt.Println("http get ERRPR:", err) return } data, err := ioutil.ReadAll(res.Body) if err != nil { fmt.Println("get data ERROR:", err) return } fmt.Println(string(data)) }

Head请求

Head请求只返回响应头。如果只想要获取一些状态信息的话,可以用Head请求。这样避免返回响应体,响应体的数据是比较多的,适合做监控。Head请求的示例:

 package main import ( "fmt" "net/http" ) var urls = []string{ "http://×××w.baidu.com", "http://×××w.google.com", "http://×××w.sina.com.cn", "http://×××w.163.com", } func main() { for _, v := range urls { resp, err := http.Head(v) if err != nil { fmt.Println("Head request ERROR:", err) continue } fmt.Println(resp.Status) } }

http 常见状态码

http.StatusContinue = 100

http.StatusOK = 200

http.StatusFound = 302 跳转

http.StatusBadRequest = 400 非法请求

http.StatusUnanthorized = 401 没有权限

http.StatusForbidden = 403 禁止访问

http.Status.NotFound = 404 页面不存在

http.StatusInternalServerError = 500 内部错误

处理form表单

 package main import ( "fmt" "io" "net/http" ) const form = ` 
` 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"][0]) // 注意上面的2个input的name是一样的 io.WriteString(w, request.Form["in"][1]) // 所以这是一个数组 io.WriteString(w, "
") io.WriteString(w, request.FormValue("in")) // 一般去一个值,就用这个方法 } } func main() { http.HandleFunc("/form", FormServer) if err := http.ListenAndServe(":8000", nil); err != nil { fmt.Println("监听端口ERROR:", err) } }

panic 处理

如果处理函数里有panic,会导致整个程序崩溃,所以要 defer revoer() 来处理 panic。在处理函数开头defer一个匿名函数:

 func FormServer(w http.ResponseWriter, request *http.Request) { // 增加一个defer来处理panic defer func() { if x := recover(); x != nil { log.Println(request.RemoteAddr, "捕获到异常:", x) } }() // 原本的处理函数的内容 w.Header().Set("content-Type", "text/html") switch request.Method { case "GET": io.WriteString(w, form) case "POST": request.ParseForm() io.WriteString(w, request.FormValue("in")) // 一般去一个值,就用这个方法 } // 搞个panic出来 zero := 0 tmp := 1 / zero io.WriteString(w, string(tmp)) }

优化统一处理

按照上面的做法,要在每个处理函数的开头都加上panic的处理。由于每个处理函数的panic处理方法都一样,所以可以写一个自定义的处理函数:

 // 自定义的panic处理的函数 func logPanics(handle http.HandlerFunc) http.HandlerFunc { return func(writer http.ResponseWriter, request *http.Request) { defer func() { if x := recover(); x != nil { log.Println(request.RemoteAddr, "捕获到异常:", x) } }() // 上面先处理panic,再接着下面调用业务逻辑 handle(writer, request) } } func main() { // http.HandleFunc("/form", FormServer) // 修改调用处理函数的方法 http.HandleFunc("/form", logPanics(FormServer)) // 把处理函数传给自己写的封装了panic处理的函数里 if err := http.ListenAndServe(":8000", nil); err != nil { fmt.Println("监听端口ERROR:", err) } }

原本直接调用处理函数。现在调用自定义的函数,把处理函数传进去。在自定义的函数里先加载defer,然后再调用执行原本的处理函数。逻辑很简单,就是把处理函数作为参数传给自定义的函数,在自定义的函数里再调用处理函数。在自定义的函数里写上defer,这样就相当于所有的处理函数都有defer了。

模板

使用模板需要用到 "text/template" 包。然后调用模板的t.Execute()方法输出。

替换

先准备一个简单的模板:

Hello {{.Name}}

Age: {{.Age}}

然后在Go里使用模板:

 package main import ( "fmt" "os" "text/template" ) type Person struct { Name string Age int } func main() { t, err := template.ParseFiles("index.html") if err != nil { fmt.Println("模板解析异常:", err) return } p := Person{"Bob", 32} if err := t.Execute(os.Stdout, p); err != nil { fmt.Println("模板加载数据异常:", err) } } /* 执行结果 PS H:\Go\src\go_dev\day10\http\use_template> go run main.go 

Hello Bob

Age: 32

PS H:\Go\src\go_dev\day10\http\use_template> */

如果直接用 {{.}} 不加字段名的话,就是输出结构体打印的效果。

输出到浏览器里

要输出到浏览器里,只需要在 t.Execute(os.Stdout, p) 里,把原本输出到终端换成输出到处理函数的 w http.ResponseWriter 类型,就好了。

html模板的内容不变,下面是go的代码:

 package main import ( "fmt" "net/http" "text/template" ) func Hello(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Hello World") } type Person struct { Name string Age int } func Index(w http.ResponseWriter, r *http.Request) { p := Person{"Cara", 18} t, err := template.ParseFiles("index.html") if err != nil { fmt.Println("加载模板ERROR:", err) return } t.Execute(w, p) } func main() { http.HandleFunc("/", Hello) http.HandleFunc("/index", Index) err := http.ListenAndServe("0.0.0.0:8000", nil) if err != nil { fmt.Println("http Listen failed") } }

判断

用法示例:

 {{if gt .Age 18}} 

已成年

{{else}}

未成年

{{end}}

更多判断逻辑:

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 小于

{{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语句就是创建一个封闭的作用域,在其范围内,{{.}}代表with的变量,而与外面的{{.}}无关,只与with的参数有关:

 {{with .Name}} 

{{.}}

{{end}}

上面这样包在 {{with .Var}} 里,with 里的 {{.}} 代表的就是 Var 这个变量。

with 可以封装常数:

 {{ with "world"}} Now the dot is set to {{ . }} {{ end }}

循环(遍历)

golang的template支持range循环来遍历map、slice内的内容,在range循环内,还可以使用$设置循环变量,我们可以通过 $i $v 来访问遍历的值。语法为:

 {{range $i, $v := .slice}} 
  • key: {{ $key }}, value: {{ $value }}
  • {{end}}

    这是另外一种遍历方式,这种方式无法访问到index或者key的值,需要通过点来访问对应的value:

     {{range .slice}} {{.field}} {{end}}

    在循环内,点是代表遍历的值。原本使用点来访问的变量,那么在循环内部就要用 $. 来访问。下面的例子表示循环内和循环外 ArticleConten 这个变量访问的方式:

     {{.ArticleContent}} {{range .slice}} {{$.ArticleContent}} {{end}}

    定义变量

    模板的参数可以是go中的基本数据类型,如字串,数字,布尔值,数组切片或者一个结构体。在模板中设置变量可以使用 $variable := value。我们在range迭代的过程使用了设置变量的方式。

     {{$article := "hello"}} {{$name := .Name}}

    mysql 使用

    这里只简单讲了数据的增删改查,所以测试代码前,需要先把数据库准备好。

    先创建一个数据库,指定了编码,这样应该可以支持中文:

     CREATE DATABASE 库名 CHARSET "utf8";

    然后建2张表:

     CREATE TABLE person ( user_id int primary key auto_increment, username varchar(260), gender varchar(260), email varchar(260) ); CREATE TABLE place ( country varchar(200), city varchar(200), telcode int );


    导入数据库驱动

    sql 包提供了通用的SQL(或类SQL)数据库接口。

    sql 包必须与数据库驱动结合使用。

    驱动包需要安装:

    go get -u github.com/go-sql-driver/mysql

    使用前,先要导入mysql的包:

     import ( "database/sql" _ "github.com/go-sql-driver/mysql" )

    上面导入了2个包。第一个是sql包,就是我们调用操作数据库用的。

    第二个是驱动包,这里前面加了占位符,所以这个包只是引入,但是不使用它。并且如果要操作别的数据库的话,只需要修改驱动包就行了。

    连接数据库

    构建连接, 格式是:”用户名:密码@tcp(IP:端口)/数据库?charset=utf8” :

     package main import ( "fmt" "time" "database/sql" _ "github.com/go-sql-driver/mysql" ) var DB *sql.DB func init() { database, err := sql.Open("mysql", "admin:admin123@tcp(192.168.3.103:3306)/Golang_week10") if err != nil { fmt.Println("连接数据库失败:", err) return }
                    
                    

    -六神源码网