zoukankan      html  css  js  c++  java
  • Golang内建库学习笔记(2)-web服务器相关

    package main
    
    import (
        "net/http"
        "fmt"
        "strings"
        "log"
    )
    
    func sayHelloName(w http.ResponseWriter, r *http.Request) {
        r.ParseForm()
        fmt.Println(r.Form)
        fmt.Println("url", r.URL.Path)
        fmt.Println("scheme", r.URL.Scheme)
        fmt.Println(r.Form["url_long"])
        for k, v:=range r.Form {
            fmt.Println("key:", k)
            fmt.Println("value:", strings.Join(v, ""))
        }
        fmt.Fprintln(w, "hello web")
    }
    
    func main()  {
        http.HandleFunc("/", sayHelloName)
        err := http.ListenAndServe(":9876", nil)
        if err!= nil {
            log.Fatal("ListenAndServe ", err)
        }
    }

    先看一个最基本的golang的web服务器代码。main中在HandleFunc中设置了路由,然后调用ListenAndServe选择监听的接口和路由方法(这里路由方法制空,即调用了默认的路由,即HandleFunc设置的路由)。

    LestenAndServe调用了http库中的serve方法,代码如下:

    func (srv *Server) Serve(l net.Listener) error {
        defer l.Close()
        if fn := testHookServerServe; fn != nil {
            fn(srv, l)
        }
        var tempDelay time.Duration // how long to sleep on accept failure
    
        if err := srv.setupHTTP2_Serve(); err != nil {
            return err
        }
    
        srv.trackListener(l, true)
        defer srv.trackListener(l, false)
    
        baseCtx := context.Background() // base is always background, per Issue 16220
        ctx := context.WithValue(baseCtx, ServerContextKey, srv)
        for {
            rw, e := l.Accept()
            if e != nil {
                select {
                case <-srv.getDoneChan():
                    return ErrServerClosed
                default:
                }
                if ne, ok := e.(net.Error); ok && ne.Temporary() {
                    if tempDelay == 0 {
                        tempDelay = 5 * time.Millisecond
                    } else {
                        tempDelay *= 2
                    }
                    if max := 1 * time.Second; tempDelay > max {
                        tempDelay = max
                    }
                    srv.logf("http: Accept error: %v; retrying in %v", e, tempDelay)
                    time.Sleep(tempDelay)
                    continue
                }
                return e
            }
            tempDelay = 0
            c := srv.newConn(rw)
            c.setState(c.rwc, StateNew) // before Serve can return
            go c.serve(ctx)
        }
    }

    可以看到,serve建立了一个循环来监听请求。在接收到连接请求后,先接受请求,然后新建了连接,并利用go新建了线程来处理新的连接。这就是golang在处理web请求上支持高并发的根本。同时也保证了每个连接的独立性。

    路由设置:

    func (sh serverHandler) ServeHTTP(rw ResponseWriter, req *Request) {
        handler := sh.srv.Handler
        if handler == nil {
            handler = DefaultServeMux
        }
        if req.RequestURI == "*" && req.Method == "OPTIONS" {
            handler = globalOptionsHandler{}
        }
        handler.ServeHTTP(rw, req)
    }

    ServeHTTP方法负责设置路由。可以看到,如果handler为空,就使用默认路由。否则就使用自定义路由。这个方法是Handler接口中规定的唯一方法。对于我们的例子,sayHelloName方法并没有实现这个方法,仍然实现了Handler接口。这是因为HandleFunc方法将路由实现方法强制转换为HandleFunc类型。该方法实现了Handler接口。

    handler处理方法如下:

    func (mux *ServeMux) handler(host, path string) (h Handler, pattern string) {
        mux.mu.RLock()
        defer mux.mu.RUnlock()
    
        // Host-specific pattern takes precedence over generic ones
        if mux.hosts {
            h, pattern = mux.match(host + path)
        }
        if h == nil {
            h, pattern = mux.match(path)
        }
        if h == nil {
            h, pattern = NotFoundHandler(), ""
        }
        return
    }

    可以看到其匹配路由的方式。

    根据以上的内容,我们也可以自己自定义路由。自定义路只需实现Handler接口。

    type MyMux struct {
    }
    
    func (m *MyMux) ServeHTTP(w http.ResponseWriter, r *http.Request)  {
        if r.URL.Path == "/" {
            sayHelloName(w, r)
            return
        }
        http.NotFound(w, r)
        return
    }
    
    func main()  {
        mux := &MyMux{}
        http.ListenAndServe(":9876", mux)
    }
  • 相关阅读:
    shell进行mysql统计
    java I/O总结
    Hbase源码分析:Hbase UI中Requests Per Second的具体含义
    ASP.NET Session State Overview
    What is an ISAPI Extension?
    innerxml and outerxml
    postman
    FileZilla文件下载的目录
    how to use webpart container in kentico
    Consider using EXISTS instead of IN
  • 原文地址:https://www.cnblogs.com/wangzhao765/p/9037614.html
Copyright © 2011-2022 走看看