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)
    }
  • 相关阅读:
    在IE和Firfox获取keycode
    using global variable in android extends application
    using Broadcast Receivers to listen outgoing call in android note
    help me!virtual keyboard issue
    using iscroll.js and iscroll jquery plugin in android webview to scroll div and ajax load data.
    javascript:jquery.history.js使用方法
    【CSS核心概念】弹性盒子布局
    【Canvas学习笔记】基础篇(二)
    【JS核心概念】数据类型以及判断方法
    【问题记录】ElementUI上传组件使用beforeupload钩子校验失败时的问题处理
  • 原文地址:https://www.cnblogs.com/wangzhao765/p/9037614.html
Copyright © 2011-2022 走看看