学习记录
- [1 使用中间件](#1 使用中间件)
-
- [1.1 测试一下](#1.1 测试一下)
- [1.2 push代码](#1.2 push代码)
- [2 URI 中的斜杆](#2 URI 中的斜杆)
-
- [2.1 StrictSlash](#2.1 StrictSlash)
- [2.2 兼容 POST 请求](#2.2 兼容 POST 请求)
1 使用中间件
代码中存在重复率很高的代码
go
w.Header().Set("Content-Type", "text/html; charset=utf-8")
统一对响应做处理的,我们可以使用中间件来做
使用中间件后的代码
go
package main
import (
"fmt"
"net/http"
"github.com/gorilla/mux"
)
func homeHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "<h1>Hello, 欢迎来到 goblog!</h1>")
}
func aboutHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "此博客是用以记录编程笔记,如您有反馈或建议,请联系 "+
"<a href=\"mailto:summer@example.com\">summer@example.com</a>")
}
func notFoundHandler(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusNotFound)
fmt.Fprint(w, "<h1>请求页面未找到 :(</h1><p>如有疑惑,请联系我们。</p>")
}
func articlesShowHandler(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
id := vars["id"]
fmt.Fprint(w, "文章 ID:"+id)
}
func articlesIndexHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "访问文章列表")
}
func articlesStoreHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "创建新的文章")
}
func forceHTMLMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// 1. 设置标头
w.Header().Set("Content-Type", "text/html; charset=utf-8")
// 2. 继续处理请求
next.ServeHTTP(w, r)
})
}
func main() {
router := mux.NewRouter()
router.HandleFunc("/", homeHandler).Methods("GET").Name("home")
router.HandleFunc("/about", aboutHandler).Methods("GET").Name("about")
router.HandleFunc("/articles/{id:[0-9]+}", articlesShowHandler).Methods("GET").Name("articles.show")
router.HandleFunc("/articles", articlesIndexHandler).Methods("GET").Name("articles.index")
router.HandleFunc("/articles", articlesStoreHandler).Methods("POST").Name("articles.store")
// 自定义 404 页面
router.NotFoundHandler = http.HandlerFunc(notFoundHandler)
// 中间件:强制内容类型为 HTML
router.Use(forceHTMLMiddleware)
// 通过命名路由获取 URL 示例
homeURL, _ := router.Get("home").URL()
fmt.Println("homeURL: ", homeURL)
articleURL, _ := router.Get("articles.show").URL("id", "1")
fmt.Println("articleURL: ", articleURL)
http.ListenAndServe(":3000", router)
}
这段代码定义了一个名为 forceHTMLMiddleware
的函数,它是一个中间件函数,接受一个 http.Handler
类型的参数 h
,并返回一个经过处理后的 http.Handler
。
让我们逐步解释这段代码的功能:
-
函数定义:
func forceHTMLMiddleware(h http.Handler) http.Handler { ... }
:这是一个函数定义,它接受一个http.Handler
类型的参数h
,表示要执行的下一个处理程序(handler),并返回一个经过处理后的http.Handler
。
-
中间件功能:
- 这个中间件的功能是强制将响应的内容类型设置为 HTML 格式,并指定字符集为 UTF-8。
w.Header().Set("Content-Type", "text/html; charset=utf-8")
:在处理请求之前,通过w.Header().Set
方法设置响应头中的Content-Type
字段为text/html; charset=utf-8
,表示响应内容为 HTML 格式,并且字符集为 UTF-8。h.ServeHTTP(w, r)
:然后调用传入的下一个处理程序h
的ServeHTTP
方法,继续处理请求并生成响应。
-
返回处理程序:
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { ... })
:返回一个匿名函数,该函数实现了http.Handler
接口的ServeHTTP
方法,用于处理请求并设置响应头。
通过使用这个中间件函数,您可以确保每个经过该中间件的请求的响应内容类型都被强制设置为 HTML 格式,并且字符集为 UTF-8。这有助于确保一致的响应格式和字符编码。您可以将这个中间件应用于您的 HTTP 处理程序链中,以实现统一的响应处理逻辑。
1.1 测试一下
localhost:3000/about
1.2 push代码
//有时因为github访问受限的原因Push失败,可开加速器后重新push
fatal: unable to access 'https://github.com/SGY321/goblog.git/': Failed to connect to github.com port 443 after 21179 ms: Couldn't connect to server
git add .
git commit -m "使用中间件"
git push
2 URI 中的斜杆
访问以下两个链接:
localhost:3000/about
localhost:3000/about/
有 / 的链接会报 404 错误:
希望 URL 后面是否加斜杆的情况下,皆使用同一个返回结果
2.1 StrictSlash
Gorilla Mux 提供了一个 StrictSlash(value bool) 函数
slash中文斜杠
浏览器再次访问 localhost:3000/about/ :
(显示成功)
可以看到当请求 about/ 时产生了两个请求,第一个是 301 跳转,第二个是跳转到的 about 去掉斜杆的链接。
浏览器在处理 301 请求时,会缓存起来。后续的 about/ 浏览器都会自动去请求 about 链接,也就是说两次请求只会在第一次的时候发生。
这个解决方案看起来不错,然而有一个严重的问题 ------ 当请求方式为 POST 的时候,遇到服务端的 301 跳转,将会变成 GET 方式。很明显,这并非所愿,我们需要一个更好的方案。
2.2 兼容 POST 请求
还原上面的修改
git checkout .
写一个函数把 Gorilla Mux 包起来,在这个函数中我们先对进来的请求做处理,然后再传给 Gorilla Mux 去解析。
go
.
.
.
func removeTrailingSlash(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// 1. 除首页以外,移除所有请求路径后面的斜杆
if r.URL.Path != "/" {
r.URL.Path = strings.TrimSuffix(r.URL.Path, "/")
}
// 2. 将请求传递下去
next.ServeHTTP(w, r)
})
}
func main() {
.
.
.
http.ListenAndServe(":3000", removeTrailingSlash(router))
}