gowebexamples学习笔记01
Go Web 开发笔记总结
本笔记根据 gowebexamples
项目的代码示例,总结 Go Web 开发中的常见操作。
ch01 - Hello World
- 核心概念: 构建最简单的 HTTP 服务器,响应客户端请求。
- 实现: 使用
net/http
包的http.HandleFunc
注册路由,http.ListenAndServe
启动服务器。 - 示例: 在根路径
/
上响应 “Hello, you’ve requested: [path]”。
1 | package main |
代码讲解:
http.HandleFunc("/", ...)
: 注册一个 HTTP 处理函数,当用户访问根路径/
时,会执行匿名函数。func(w http.ResponseWriter, r *http.Request)
: 这是 HTTP 处理函数的签名,w
用于写入响应,r
包含请求信息。fmt.Fprintf(w, ...)
: 将格式化的字符串写入 HTTP 响应。http.ListenAndServe(":8080", nil)
: 启动一个 HTTP 服务器,监听在8080
端口。nil
表示使用默认的 ServeMux。
ch02 - HTTP Server
- 核心概念: 在 HTTP 服务器中提供静态文件服务。
- 实现: 使用
http.FileServer
创建文件服务器,http.StripPrefix
移除 URL 前缀,然后通过http.Handle
注册到特定路径。 - 示例: 将
static/
目录下的文件通过/static/
路径暴露。
1 | package main |
代码讲解:
http.FileServer(http.Dir("static/"))
: 创建一个文件服务器,它会从static/
目录下提供文件。http.StripPrefix("/static/", fs)
: 移除请求 URL 中的/static/
前缀,这样文件服务器就能正确地找到static/
目录下的文件。http.Handle("/static/", ...)
: 将文件服务器注册到/static/
路径,所有以/static/
开头的请求都会由这个文件服务器处理。
ch03 - Routing
- 核心概念: 路由是根据 URL 路径将请求分发到不同的处理函数。虽然示例代码为空,但在实际应用中,路由是构建复杂 Web 应用的基础。
- 常用库:
gorilla/mux
是一个流行的第三方路由库,提供了更强大的路由匹配和中间件支持。
1 | package main |
代码讲解:
mux.NewRouter()
: 创建一个新的mux
路由器。r.HandleFunc("/products/{key}", ProductHandler)
: 注册一个带有路径参数的路由。{key}
是一个占位符,可以匹配任何值。ProductHandler
: 处理/products/{key}
路径的请求。mux.Vars(r)
: 从请求中提取路径参数。http.ListenAndServe(":8080", r)
: 启动 HTTP 服务器并使用mux
路由器处理请求。
ch04 - Database
- 核心概念: Go 语言中数据库操作,以 MySQL 为例,涵盖连接、创建表、插入、查询和删除等基本 CRUD 操作。
- 实现: 使用
database/sql
包进行数据库交互,通过_ "github.com/go-sql-driver/mysql"
导入 MySQL 驱动。 - 操作:
sql.Open
: 连接数据库。db.Ping
: 检查数据库连接。db.Exec
: 执行 DDL (如CREATE TABLE
) 和 DML (如INSERT
,DELETE
) 语句。db.QueryRow
: 查询单行数据。db.Query
: 查询多行数据。
1 | package main |
代码讲解:
sql.Open("mysql", ...)
: 打开一个到 MySQL 数据库的连接。请替换连接字符串中的root:password@(localhost:3306)/database
为您的实际数据库凭据。db.Ping()
: 验证数据库连接是否仍然活跃。db.Exec(query)
: 执行 SQL 语句,例如创建表或插入数据。对于INSERT
操作,res.LastInsertId()
可以获取新插入行的 ID。
ch05 - Template
- 核心概念: 使用 Go 的
html/template
包进行 HTML 模板渲染,将动态数据填充到 HTML 页面中。 - 实现:
template.ParseFiles
: 解析模板文件。template.Must
: 辅助函数,用于处理模板解析错误。tmp.Execute
: 将数据与模板结合并写入http.ResponseWriter
。
- 数据结构: 定义结构体来封装需要传递给模板的数据。
- 常用库:
gorilla/mux
用于路由。
1 | package main |
代码讲解:
type Todo struct{...}
和type TodoPageData struct{...}
: 定义了用于模板渲染的数据结构。template.Must(template.ParseFiles("layout.html"))
: 解析名为layout.html
的模板文件。template.Must
会在解析失败时 panic。tmp.Execute(w, data)
: 将data
结构体中的数据填充到模板中,并将结果写入http.ResponseWriter
。
ch06 - Asset and File
- 核心概念: 提供静态资源(如 CSS、JavaScript、图片)服务,与 ch02 类似,但更侧重于“资产”的概念。
- 实现: 同样使用
http.FileServer
和http.StripPrefix
。 - 示例: 将
asset/
目录下的文件通过/static/
路径暴露。
1 | package main |
代码讲解:
http.FileServer(http.Dir("asset/"))
: 创建一个文件服务器,用于提供asset/
目录下的静态文件。http.StripPrefix("/static/", fs)
: 移除请求 URL 中的/static/
前缀,确保文件服务器能正确映射到asset/
目录。http.Handle("/static/", ...)
: 将文件服务器注册到/static/
路径,使得所有/static/
开头的请求都由该文件服务器处理。
ch07 - Form
- 核心概念: 处理 HTML 表单提交,获取表单数据。
- 实现:
- 根据 HTTP 请求方法 (
r.Method
) 判断是 GET 请求(显示表单)还是 POST 请求(处理表单数据)。 - 使用
r.FormValue("field_name")
获取表单字段的值。
- 根据 HTTP 请求方法 (
- 模板: 结合
html/template
来渲染表单页面和显示提交结果。
1 | package main |
代码讲解:
type ContactDetail struct{...}
: 定义一个结构体来存储表单提交的数据。tmpl := template.Must(template.ParseFiles("forms.html"))
: 解析用于显示表单的 HTML 模板。if r.Method != http.MethodPost
: 判断请求方法,如果是 GET 请求则显示表单,如果是 POST 请求则处理表单数据。r.FormValue("email")
: 获取表单中name="email"
的字段值。FormValue
会自动解析application/x-www-form-urlencoded
和multipart/form-data
类型的表单数据。
ch08 - Middleware
- 核心概念: 中间件是在请求到达最终处理函数之前或之后执行的代码,用于实现日志记录、认证、压缩等横切关注点。
- 基本实现: 通过包装
http.HandlerFunc
来实现简单的中间件,例如日志记录。 - 高级实现: 定义
Middleware
类型 (func(http.HandlerFunc) http.HandlerFunc
),并实现Chain
函数来链式调用多个中间件,提供更灵活的中间件管理。
1 | package main |
代码讲解:
type Middleware func(http.HandlerFunc) http.HandlerFunc
: 定义了一个Middleware
类型,它是一个函数,接受一个http.HandlerFunc
并返回一个新的http.HandlerFunc
。Logging() Middleware
: 这是一个中间件工厂函数,它返回一个Middleware
类型的函数。这个中间件会在处理请求前后记录日志。Chain(f http.HandlerFunc,ms... Middleware) http.HandlerFunc
: 这个函数将多个中间件按顺序应用到一个http.HandlerFunc
上,形成一个处理链。请求会依次经过每个中间件,最后到达最终的处理函数f
。
ch09 - Sessions
- 核心概念: 会话管理,用于在多个 HTTP 请求之间维护用户状态。
- 实现: 使用
github.com/gorilla/sessions
库。 - 操作:
sessions.NewCookieStore
: 创建基于 Cookie 的 session 存储。store.Get
: 获取或创建一个 session。session.Values
: 存储 session 数据。session.Save
: 保存 session 到客户端 Cookie。
- 示例: 模拟用户登录、登出和访问受保护的资源。
1 | package main |
代码讲解:
sessions.NewCookieStore(key)
: 创建一个新的 Cookie 存储,key
用于加密 session 数据。store.Get(r, "cookie-name")
: 从请求中获取名为 “cookie-name” 的 session。如果不存在,则创建一个新的。session.Values["authenticated"] = true
: 在 session 中设置一个键值对,表示用户已认证。session.Save(r, w)
: 将 session 的更改保存到客户端的 Cookie 中。secret
函数通过检查session.Values["authenticated"]
来判断用户是否登录,从而保护敏感资源。
ch10 - JSON
- 核心概念: 处理 JSON 数据的编码(Go 对象转 JSON 字符串)和解码(JSON 字符串转 Go 对象)。
- 实现: 使用
encoding/json
包。 - 操作:
json.NewDecoder(r.Body).Decode(&user)
: 从请求体中解码 JSON 到 Go 结构体。json.NewEncoder(w).Encode(data)
: 将 Go 结构体编码为 JSON 并写入响应体。
- 结构体标签: 使用
json:"field_name"
标签来控制 JSON 字段名。
1 | package main |
代码讲解:
type User struct{...}
: 定义一个结构体,用于映射 JSON 数据。json:"..."
标签指定了结构体字段对应的 JSON 键名。json.NewDecoder(r.Body).Decode(&user)
: 创建一个 JSON 解码器,从请求体r.Body
中读取 JSON 数据并解码到user
结构体中。json.NewEncoder(w).Encode(peter)
: 创建一个 JSON 编码器,将peter
结构体编码为 JSON 格式,并写入响应体w
。
ch11 - Websocket
- 核心概念: 实现全双工通信协议 WebSocket,用于实时应用。
- 实现: 使用
github.com/gorilla/websocket
库。 - 操作:
websocket.Upgrader
: 配置 WebSocket 升级器,例如CheckOrigin
用于跨域检查。upgrader.Upgrade
: 将 HTTP 连接升级为 WebSocket 连接。conn.ReadMessage
: 读取 WebSocket 消息。conn.WriteMessage
: 发送 WebSocket 消息。
- 示例: 实现一个简单的 WebSocket 回显服务器,并将
websockets.html
作为客户端页面。
1 | package main |
代码讲解:
websocket.Upgrader
: 用于将普通的 HTTP 连接升级为 WebSocket 连接。CheckOrigin
设置为true
允许跨域连接(生产环境中应谨慎设置)。upgrader.Upgrade(w, r, nil)
: 执行连接升级操作,成功后返回一个*websocket.Conn
对象,代表 WebSocket 连接。conn.ReadMessage()
: 从 WebSocket 连接中读取消息。它返回消息类型、消息数据和可能的错误。conn.WriteMessage(msgType, msg)
: 向 WebSocket 连接写入消息,将接收到的消息原样发送回客户端,实现了“回显”功能。
ch12 - Password Hashing
- 核心概念: 使用安全的哈希算法存储用户密码,而不是明文存储,以提高安全性。
- 实现: 使用
golang.org/x/crypto/bcrypt
包。 - 操作:
bcrypt.GenerateFromPassword
: 生成密码哈希。bcrypt.CompareHashAndPassword
: 比较明文密码和哈希值是否匹配。
- 安全性:
bcrypt
是一种自适应的哈希函数,可以抵御彩虹表攻击和暴力破解。
1 | package main |
代码讲解:
bcrypt.GenerateFromPassword([]byte(pwd), 14)
: 使用 bcrypt 算法对密码进行哈希。第二个参数14
是成本因子(cost factor),值越大,哈希计算越慢,安全性越高,但也会消耗更多计算资源。bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
: 比较明文密码和哈希值是否匹配。这个函数会处理哈希和盐值的提取,并进行安全的比较,防止时序攻击。