通過幾個例子來學習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 協議》,轉載必須註明作者和本文連結