go http 包练习

天空蓝雨 · · 609 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

参见:
下载包 设置代理
妈的,下载包有时能下,有时候就卡住。
手动安装包

Go 的 http 包详解

https://golang.org/pkg/net/http/

几个官方的例子,拿来练习一下,wc, 体会到了 go http 包的强大之处:
下面是一些例子,来主要讲解下面的几个函数
FileServer
FileServer (DotFileHiding)
FileServer (StripPrefix)
Get
Handle
HandleFunc
Hijacker
ListenAndServe
ListenAndServeTLS
NotFoundHandler
ResponseWriter (Trailers)
ServeMux.Handle
Server.Shutdown
StripPrefix

主体结构是:

func main(){
    FileServer()
        ...
}

我把每个函数的例子,封装为一个函数 然后放在 main 函数里面执行一下。main 都是重复的,所以就不贴代码了。(联系 采用 subline,炒鸡方便)

  • FileServer
func FileServer(root FileSystem) Handler

这个函数也是很牛逼, 主要是可以把文件路径映射为 url 路由。
https://golang.org/pkg/net/http/#FileServer
实现原理:
https://shockerli.net/post/golang-pkg-http-file-server/

使用 FileSystem 接口 root 提供文件访问服务的 HTTP 处理器。可以方便的实现静态文件服务器

func FileServer(){
    http.ListenAndServe(":8081", http.FileServer(http.Dir("F:/go/")))

}

运行效果:


注意多次运行,可能需要更改端口号

点击 go_practice 链接(文件夹)

点击 http_pkg.go

上面是个简单的 可以展示文件目录的功能,go 底层,帮我们实现了 文件读取和展示。

支持子目录路径
只是比上面多了个 自定义路由前缀

http.StripPrefix() 方法配合 http.Handle() 或 http.HandleFunc() 可以实现带路由前缀的文件服务。

func FileServer(){
    // 
    // http.ListenAndServe(":8081", http.FileServer(http.Dir("F:/go/")))
    http.Handle("/tmpfiles/", http.StripPrefix("/tmpfiles/", http.FileServer(http.Dir("F:/go/"))))

    http.ListenAndServe(":8082", nil)
}

运行效果:


会比第一个程序多一个 tmpfiles 路径前缀
  • Handle

func Handle(pattern string, handler Handler)

路由匹配处理函数, 要实现 Handler 接口的 ServeHTTP(w http.ResponseWriter, r *http.Request) 方法

package main

import (
    "fmt"
    "log"
    "net/http"
    "sync"
)

type countHandler struct {
    mu sync.Mutex // guards n
    n  int
}

func (h *countHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    h.mu.Lock()
    defer h.mu.Unlock()
    h.n++
    fmt.Fprintf(w, "count is %d\n", h.n)
}

func main() {
    http.Handle("/count", new(countHandler))
    log.Fatal(http.ListenAndServe(":8080", nil))
}

  • HandleFunc

func HandleFunc(pattern string, handler func(ResponseWriter, *Request))

和 Handle 几乎一样,唯一不同的是参数不一样,这个是自己定义一个
xx(w http.ResponseWriter, r *http.Request) 这样的函数,儿不必叫 ServeHTTP 名字,因为 HandleFunc 函数第二个参数是 直接一个函数类型,二不是 有ServeHTTP 函数的 Handler 接口类型

func simple_server(){

    http.HandleFunc("/my_name", name_haddler)

    http.HandleFunc("/url", func(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "<h1>Hello, %q</h1>", html.EscapeString(r.URL.Path))
    })

    http.ListenAndServe(":8080", nil)
}

func name_haddler(w http.ResponseWriter, r *http.Request){
    fmt.Fprintf(w, "<h1>hello yxl</h1>")
}
  • ListenAndServe

 func ListenAndServe(addr string, handler Handler) error 

第二个参数通常为 nil, 在这种情况下,使用DefaultServeMux。

func simple_server(){

    http.HandleFunc("/my_name", name_haddler)

    http.HandleFunc("/url", func(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "<h1>Hello, %q</h1>", html.EscapeString(r.URL.Path))
    })

    http.ListenAndServe(":8080", nil)
}

func name_haddler(w http.ResponseWriter, r *http.Request){
    fmt.Fprintf(w, "<h1>hello yxl</h1>")
}
  • ListenAndServeTLS

func ListenAndServeTLS(addr, certFile, keyFile string, handler Handler) error

ListenAndServe HTTPS 版本

  • NotFoundHandler

404 对应的处理

func NotFoundHandler() Handler
func NotFoundHandler(){
    // 404 对应的处理
    mux.Handle("/resources", http.NotFoundHandler())

}
  • ResponseWriter

一个接口

定义源码如下:

<pre style="font-family: Menlo, monospace; font-size: 0.875rem; line-height: 1.4; overflow-x: auto; margin: 1.25rem; background: rgb(239, 239, 239); padding: 0.625rem; border-radius: 0.3125rem; color: rgb(62, 64, 66); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: left; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">type ResponseWriter interface {
    // Header returns the header map that will be sent by
    // WriteHeader. The Header map also is the mechanism with which
    // Handlers can set HTTP trailers.
    //
    // Changing the header map after a call to WriteHeader (or
    // Write) has no effect unless the modified headers are
    // trailers.
    //
    // There are two ways to set Trailers. The preferred way is to
    // predeclare in the headers which trailers you will later
    // send by setting the "Trailer" header to the names of the
    // trailer keys which will come later. In this case, those
    // keys of the Header map are treated as if they were
    // trailers. See the example. The second way, for trailer
    // keys not known to the Handler until after the first Write,
    // is to prefix the Header map keys with the TrailerPrefix
    // constant value. See TrailerPrefix.
    //
    // To suppress automatic response headers (such as "Date"), set
    // their value to nil.
    Header() [Header](https://golang.org/pkg/net/http/#Header)

    // Write writes the data to the connection as part of an HTTP reply.
    //
    // If WriteHeader has not yet been called, Write calls
    // WriteHeader(http.StatusOK) before writing the data. If the Header
    // does not contain a Content-Type line, Write adds a Content-Type set
    // to the result of passing the initial 512 bytes of written data to
    // DetectContentType. Additionally, if the total size of all written
    // data is under a few KB and there are no Flush calls, the
    // Content-Length header is added automatically.
    //
    // Depending on the HTTP protocol version and the client, calling
    // Write or WriteHeader may prevent future reads on the
    // Request.Body. For HTTP/1.x requests, handlers should read any
    // needed request body data before writing the response. Once the
    // headers have been flushed (due to either an explicit Flusher.Flush
    // call or writing enough data to trigger a flush), the request body
    // may be unavailable. For HTTP/2 requests, the Go HTTP server permits
    // handlers to continue to read the request body while concurrently
    // writing the response. However, such behavior may not be supported
    // by all HTTP/2 clients. Handlers should read before writing if
    // possible to maximize compatibility.
    Write([][byte](https://golang.org/pkg/builtin/#byte)) ([int](https://golang.org/pkg/builtin/#int), [error](https://golang.org/pkg/builtin/#error))

    // WriteHeader sends an HTTP response header with the provided
    // status code.
    //
    // If WriteHeader is not called explicitly, the first call to Write
    // will trigger an implicit WriteHeader(http.StatusOK).
    // Thus explicit calls to WriteHeader are mainly used to
    // send error codes.
    //
    // The provided code must be a valid HTTP 1xx-5xx status code.
    // Only one header may be written. Go does not currently
    // support sending user-defined 1xx informational headers,
    // with the exception of 100-continue response header that the
    // Server sends automatically when the Request.Body is read.
    WriteHeader(statusCode [int](https://golang.org/pkg/builtin/#int))
}</pre>


其他的暂时就不讲了,太难了,老铁
完整总结的代码(其实和上面一样的):

package main 
/* http 包的练习 */
import (
    "fmt"
    "net/http"
    "io/ioutil"
    "html"
    _ "log"
)

func easy_test(url string){
    resp, err := http.Get(url)
    if err != nil{
        fmt.Printf("%v", err)
        return 
    }
    defer resp.Body.Close()  // 入站是当前内存区域的 执行, 和主函数分开的,每个块内存都可以有自己的 压栈
    defer fmt.Printf("请求函数执行结束")
    body, _ := ioutil.ReadAll(resp.Body)
    fmt.Printf("%s", body)
    return 
}

func simple_server(){

    http.HandleFunc("/my_name", name_haddler)

    http.HandleFunc("/url", func(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "<h1>Hello, %q</h1>", html.EscapeString(r.URL.Path))
    })

    http.ListenAndServe(":8080", nil)
}

func name_haddler(w http.ResponseWriter, r *http.Request){
    fmt.Fprintf(w, "<h1>hello yxl</h1>")
}


// 事例
// FileServer
// FileServer (DotFileHiding)
// FileServer (StripPrefix)
// Get
// Handle
// HandleFunc
// Hijacker
// ListenAndServe
// ListenAndServeTLS
// NotFoundHandler
// ResponseWriter (Trailers)
// ServeMux.Handle
// Server.Shutdown
// StripPrefix

// FileServer  func FileServer(root FileSystem) Handler
func FileServer(){
    
    http.ListenAndServe(":8081", http.FileServer(http.Dir("F:/go/")))
    
}

// FileServer (DotFileHiding)  
func FileServer_DotFileHiding(){
    // 这个看不懂啊

}

// FileServer (StripPrefix)  
func FileServer_StripPrefix(){
    // 这个就是子在 FileServer 基础上加了一个前缀路由地址
    http.Handle("/tmpfiles/", http.StripPrefix("/tmpfiles/", http.FileServer(http.Dir("F:/go/"))))
    http.ListenAndServe(":8082", nil)
}

// Get func Get(url string) (resp *Response, err error)
func get(){
    // 请求一个地址, 如果状态码是 30x  x 是12378之一 就自动重定向,最多 10 次
    // 参见 11 行 easy_test

}

// Handle  func Handle(pattern string, handler Handler)
func handle(){
    // 就是添加路由,匹配对应一个函数酱紫
    // 这个就暂时补贴代码了
    // 路由匹配处理函数(结构体类型), 要实现 Handler 接口的 ServeHTTP(w http.ResponseWriter, r *http.Request)  方法 


}

// HandleFunc  func HandleFunc(pattern string, handler func(ResponseWriter, *Request))
func HandleFunc(){
    // 和 Handle 几乎一样,唯一不同的是参数不一样,这个是自己定义一个 
    // xx(w http.ResponseWriter, r *http.Request) 这样的函数,儿不必叫 ServeHTTP 名字,因为 HandleFunc 函数第二个参数是 直接一个函数类型,二不是  有ServeHTTP 函数的 Handler  接口类型
    // 参见 simple_server  24-37 行

}

// ListenAndServe  func ListenAndServe(addr string, handler Handler) error 
func ListenAndServe(){
    // 参见 

}


// ListenAndServeTLS  func ListenAndServeTLS(addr, certFile, keyFile string, handler Handler) error
func ListenAndServeTLS(){
    // ListenAndServe  HTTPS 版本

}

// NotFoundHandler  func NotFoundHandler() Handler
func NotFoundHandler(){
    // 404 对应的处理
    mux.Handle("/resources", http.NotFoundHandler())

}

// ResponseWriter   interface 
func ResponseWriter(){
    // 上面所有的 处理函数,都直接或者间接实现这个 函数了
    // 如: func(w http.ResponseWriter, r *http.Request)
    // 还有 Handler 接口定义的 ServeHTTP(ResponseWriter, *Request) 函数(同包就省略了 http.)


}

// func (*ServeMux) ServeMux      func (mux *ServeMux) Handle(pattern string, handler Handler)
func ServeMux_ServeMux(){
    // 这个不太懂

}

// func (*Server) Shutdown    func (srv *Server) Shutdown(ctx context.Context) error
func Server_Shutdown(){
    // 这个也不会


}

// StripPrefix   func StripPrefix(prefix string, h Handler) Handler
func StripPrefix(){
    // 删除请求的特定前缀 
    // 参见:  FileServer_StripPrefix  70 行

}


func main(){
    // easy_test("https://sunrain.xyz")
    // simple_server()
    FileServer()
}


有疑问加站长微信联系(非本文作者)

本文来自:简书

感谢作者:天空蓝雨

查看原文:go http 包练习

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

609 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传