标准库 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。
默认的handlernil,在这种情况下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!")
    })
}
go
本作品采用《CC 协议》,转载必须注明作者和本文链接
日拱一卒,功不唐捐
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!