标准库 http 包的简单实用
通过几个例子来学习http包的简单实用
构建一个静态的文件服务器
func FileServer(root FileSystem) Handler
如果需要使用操作系统的文件系统,可以使用http.Dir
http.Handler(http.FileServer(http.Dir("/tmp")))
Example
package main
import (
"log"
"net/http"
)
func main() {
log.Fatal(http.ListenAndServe(":8080", http.FileServer(http.Dir("/Users/iamcyan/go_project/demo"))))
}
本地请求结果:
➜ demo pwd
/Users/iamcyan/go_project/demo
➜ demo tree
.
├── fmt.go
├── http.go
└── test
└── a.txt
1 directory, 3 files
➜ demo curl http://localhost:8080/
<pre>
<a href=".idea/">.idea/</a>
<a href="fmt.go">fmt.go</a>
<a href="http.go">http.go</a>
<a href="test/">test/</a>
</pre>
➜ demo curl http://localhost:8080/test/
<pre>
<a href="a.txt">a.txt</a>
</pre>
➜ demo curl http://localhost:8080/test/a.txt
111
可以静态文件的访问设置路由前缀,比如我们给前面的路由加上前缀、doc/,能够返回同样的结果,代码如下:
package main
import (
"log"
"net/http"
)
func main() {
http.Handle("/doc/", http.StripPrefix("/doc/", http.FileServer(http.Dir("/Users/iamcyan/go_project/demo"))))
log.Fatal(http.ListenAndServe(":8080", nil))
}
返回示例:
➜ demo pwd
/Users/iamcyan/go_project/demo
➜ demo tree
.
├── fmt.go
├── http.go
└── test
└── a.txt
1 directory, 3 files
➜ demo curl http://localhost:8080/doc/
<pre>
<a href=".idea/">.idea/</a>
<a href="fmt.go">fmt.go</a>
<a href="http.go">http.go</a>
<a href="test/">test/</a>
</pre>
➜ demo curl http://localhost:8080/doc/test/
<pre>
<a href="a.txt">a.txt</a>
</pre>
➜ demo
发送GET请求
func Get(url string) (resp *Response, err error)
返回下列code时,进行重定向,最大的重定向次数为10次。
301 (Moved Permanently)
302 (Found)
303 (See Other)
307 (Temporary Redirect)
308 (Permanent Redirect)
Example
func main() {
resp, err := http.Get("http://www.google.com/robots.txt")
if err != nil {
log.Fatal(err)
}
robots, err := ioutil.ReadAll(resp.Body)
resp.Body.Close()
if err != nil {
log.Fatal(err)
}
fmt.Printf("%s", robots)
}
注意:body 如何读取、body 读取完成之后必须关闭
Handle
handle方法可以将路由处理handler
注册进DefaultServeMux
type countHandler struct {
mu sync.Mutex
c int
}
func (h *countHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
h.mu.Lock()
defer h.mu.Unlock()
h.c++
fmt.Fprintf(w, "count is %d\n", h.c)
}
func main() {
http.Handle("/count", new(countHandler))
log.Fatal(http.ListenAndServe(":8080", nil))
}
HandleFunc
handle方法可以将路由处理handler function
注册进DefaultServeMux
package main
import (
"io"
"log"
"net/http"
)
func main() {
h1 := func(w http.ResponseWriter, _ *http.Request) {
io.WriteString(w, "Hello from a HandleFunc #1!\n")
}
h2 := func(w http.ResponseWriter, _ *http.Request) {
io.WriteString(w, "Hello from a HandleFunc #2!\n")
}
http.HandleFunc("/", h1)
http.HandleFunc("/endpoint", h2)
log.Fatal(http.ListenAndServe(":8080", nil))
}
ListenAndServe
func ListenAndServe(addr string, handler Handler) error
监听网络端口,当连接到达时会调用handler
处理程序。会开启TCP keep-alive。
默认的handler
是nil
,在这种情况下DefaultServeMux
会被调用。
NotFoundHandler
func NotFoundHandler() Handler
Example
func main() {
log.Fatal(http.ListenAndServe(":8080", http.NotFoundHandler()))
}
type ResponseWriter
ResponseWriter
接口用于 http 处理器生成HTTP 返回
在 Handler.ServerHTTP
返回后,ResponseWriter
不在被使用
实现改接口,需要实现3个方法
type ResponseWriter interfack {
//设置http返回头,如 Header().Set()
Header() Header
Write([]byte) (int, err)
//发送http状态码
WriteHeader(statusCode int)
}
Example
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/test", func(w http.ResponseWriter, req *http.Request) {
// Before any call to WriteHeader or Write, declare
// the trailers you will set during the HTTP
// response. These three headers are actually sent in
// the trailer.
w.Header().Set("Trailer", "AtEnd1, AtEnd2")
w.Header().Add("Trailer", "AtEnd3")
w.Header().Set("Content-Type", "text/plain; charset=utf-8") // normal header
w.WriteHeader(http.StatusOK)
w.Header().Set("AtEnd1", "value 1")
io.WriteString(w, "This HTTP response has both headers before this text and trailers at the end.\n")
w.Header().Set("AtEnd2", "value 2")
w.Header().Set("AtEnd3", "value 3") // These will appear as trailers.
})
}
请求返回:
➜ demo curl -v http://localhost:8080/test
* Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 8080 (#0)
> GET /test HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.64.1
> Accept: */*
>
< HTTP/1.1 200 OK
< Content-Type: text/plain; charset=utf-8
< Trailer: AtEnd1, AtEnd2
< Trailer: AtEnd3
< Date: Sun, 27 Dec 2020 05:36:51 GMT
< Transfer-Encoding: chunked
<
This HTTP response has both headers before this text and trailers at the end.
* Connection #0 to host localhost left intact
* Closing connection 0
func(*ServeMux) Handle
func (mux *ServeMux) Handle(pattern string, handler Handler)
type apiHandler struct{}
func (apiHandler) ServeHTTP(http.ResponseWriter, *http.Request) {}
func main() {
mux := http.NewServeMux()
mux.Handle("/api/", apiHandler{})
mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
// The "/" pattern matches everything, so we need to check
// that we're at the root here.
if req.URL.Path != "/" {
http.NotFound(w, req)
return
}
fmt.Fprintf(w, "Welcome to the home page!")
})
}
本作品采用《CC 协议》,转载必须注明作者和本文链接