-
Notifications
You must be signed in to change notification settings - Fork 0
02 goweb学习笔记
Jinxin Chen edited this page Dec 11, 2019
·
1 revision
参考网址:
func handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Hello world!", r.URL.Path)
}
func main() {
// 路由
// HandleFunc会帮忙建立handler
http.HandleFunc("/", handler)
// 监听端口
// 如果地址为空,表示默认80端口
// nil 代表使用默认的多路复用器
http.ListenAndServe(":8080", nil)
}
方法2,实现ServeHTTP接口
type myHandler struct {
}
func (h *myHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Hello world!", r.URL.Path)
}
func main() {
myHandler := myHandler{}
http.Handle("/", &myHandler)
http.ListenAndServe(":8080", nil)
// 方法3:使用http.Server
server := http.Server{
Addr: ":8080",
Handler: &myHandler,
ReadTimeout: 3 * time.Second,
}
server.ListenAndServe()
// 方法4:自定义mux
mux := http.NewServeMux()
mux.HandleFunc("/", handler)
http.ListenAndServe(":8080", mux)
}
方法3:使用http.Server,上面
方法4:自定义mux,上面
http1.1允许浏览器拿到当前页面请求的所有资源以后才断开连接,提高了效率,1.0每个资源请求都需要建立一个单独的连接
报文头部
空行(回车+换行,16进制)
报文主体
- 1xx:请求已被成功接收,继续处理
- 2xx:请求已经成功接收
- 3xx:重定向
- 4xx:客户端错误
- 5xx:服务器端错误
包:github.com/go-sql-driver/mysql
type DB
- 自动维护连接
- 自动维护连接池
- 自动将事务绑定到单个连接
// utils.go
package utils
import (
"database/sql"
_ "github.com/go-sql-driver/mysql"
)
var (
DB *sql.DB
err error
)
func init() {
DB, err = sql.Open("mysql", "root:example@tcp(xxxxx:3306)/Test_Go")
if err != nil {
panic(err.Error())
}
}
// utils.go
package utils
import (
"database/sql"
_ "github.com/go-sql-driver/mysql"
)
var (
DB *sql.DB
err error
)
func init() {
DB, err = sql.Open("mysql", "root:example@tcp(xxxxx:3306)/Test_Go")
if err != nil {
panic(err.Error())
}
}
// main.go
// 方法1:使用Prepare
func insertUser1() {
str := "insert into Users (Name, Age) values (?,?)"
cmd, err := utils.DB.Prepare(str)
if err != nil {
fmt.Printf(err.Error())
}
_, err = cmd.Exec("Jinxin", 33)
if err != nil {
fmt.Printf(err.Error())
}
}
// 方法2:直接调用db的Exec
func insertUser2() {
str := "insert into Users (Name, Age) values (?,?)"
_, err := utils.DB.Exec(str, "Huabing", 29)
if err != nil {
fmt.Printf(err.Error())
}
}
注意,row.Scan中传递的参数个数和顺序必须和select语句里面返回的字段个数和顺序相同,否则会报错
func (u *User) QueryUserByID(id int) (*User, error) {
str := "select Name, Age from Users where id=?"
row := utils.DB.QueryRow(str, id)
user := &User{}
var (
Name string
Age int
)
err := row.Scan(&Name, &Age)
if err != nil {
fmt.Printf(err.Error())
return nil, err
}
user.ID = id
user.Name = Name
user.Age = Age
return user, nil
}
- 文件名必须以 _test.go 结尾,前缀一般写为需要测试的文件名
- 测死方法必须满足格式: TestXxx,注意大小写
可以用 t.Run 来执行子测试,用TestMain方法来执行一些初始化操作
func TestMain(t *testing.M) {
fmt.Printf("Initial test")
t.Run()
}
func TestUser(t *testing.T) {
t.Run("Test add user", testAddUser)
t.Run("Test delete user", testDeleteUser)
}
func testAddUser(t *testing.T) {
user := &User{}
user.InsertUser1()
user.InsertUser2()
}
func testDeleteUser(t *testing.T) {
...
}
执行测试:
go test [-v]
net/http包
type Request
PostForm字段,获取Post的参数, url.Values类型,必须先调用Request.ParseForm方法
如果enctype=multipart/form-data(文件上传),则需要通过MultipartForm字段
FormValue和PostFormValue来直接获取参数,必要时会隐式调用ParseForm/ParseMultipartForm方法
- w.Write([]byte("hello world"))
- w.Write([]byte(
<header>...</header>
)) - 返回json,w.Header().Set("Content-Type", "application/json")
重定向:
//必须先设置header再设置302
w.Header().Set("Location", "http://www.baidu.com")
w.WriteHeader(302)
text/template, html/template
package main
import "http/template"
import "net/http"
func handler(w http.ResponseWriter, r *http.Request) {
t, _ := template.ParseFiles("index.html")
// template.ParseGlob("*.html") // 解析多个文件
t.Execute(w, "")
// t.ExecuteTemplate(w, "index2.html") // 执行index2.html模板
}
func main() {
// 处理静态资源
http.HandleFunc("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("views/static/"))))
// 直接去html页面
http.HandleFunc("/pages/", http.StripPrefix("/pages/", http.FileServer(http.Dir("views/pages/"))))
http.HandleFunc("/", &handler)
http.ListenAndServe(":8080", nil)
}
可以用template.Must方法来处理模板的错误
// index.html
}
传过来的是true
{{else}}
传过来的不是true
{{end}}
{{range .}}
// 这里的.和上面的.不同
遍历的元素是 {{.}} </br>
值有 {{.ID}} </br>
值有 {{.Name}} </br>
{{else}}
没有元素
{{end}}
// 另一种遍历方式,设置变量
{{range $k, $v := .}}
键是{{$k}} 值是{{$v}}
{{end}}
{{with "修改一下"}}
修改后的值 {{.}}
{{end}}
{{with ""}}
修改后的值 {{.}}
{{else}}
原来的值 {{.}}
{{end}}
一个模板里面包含另外一个模板
{{template: "share.html"}}
{{template: "details.html", arg}}
定义网页布局,抽象出相同内容
{{define "_layout"}}
<html>
<head></head>
<body>
{{template "content"}}
{{end}}
</body>
</html>
{{end}}
{{define "content"}}
{{end}}
定义默认模板
{{define "_layout"}}
<html>
<head></head>
<body>
{{block "content"}}
这是默认的模板,可以被覆盖
{{end}}
</body>
</html>
{{end}}
cookie1 = http.Cookie{
Name: "User",
Value: "Admin",
MaxAge: 60, // 60秒过期
}
// 没有设置过期,默认会话级别
cookie2 = http.Cookie{
Name: "User",
Value: "Operator",
}
// 方法1
w.Header().Set("Set-Cookie", cookie1.String())
// 方法2
http.SetCookie(w, &cookie2)
// 方法1
cookies := r.Header["cookie"]
// 方法2
cookie, _ := r.Cookie("User")
cookie.MaxAge = -1 // 任何小于0的值
http.SetCookie(w, &cookie)