美文网首页
go http 包练习

go http 包练习

作者: 天空蓝雨 | 来源:发表于2020-07-12 11:42 被阅读0次

    参见:
    下载包 设置代理
    妈的,下载包有时能下,有时候就卡住。
    手动安装包
    使用 go module 管理包
    go-module 命令介绍

    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 包练习

          本文链接:https://www.haomeiwen.com/subject/jcwbcktx.html