在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ GO/ 3.3 Go如何使得Web工作
7 文本處理
3 Web基礎(chǔ)
14 擴(kuò)展Web框架
10.4 小結(jié)
2.2 Go基礎(chǔ)
2.8 總結(jié)
6.1 session和cookie
5.5 使用beedb庫進(jìn)行ORM開發(fā)
8.3 REST
13.6 小結(jié)
5.4 使用PostgreSQL數(shù)據(jù)庫
14.6 pprof支持
14.1 靜態(tài)文件支持
11.2 使用GDB調(diào)試
7.7 小結(jié)
1 GO環(huán)境配置
14.5 多語言支持
7.1 XML處理
1.5 總結(jié)
13 如何設(shè)計(jì)一個(gè)Web框架
14.3 表單及驗(yàn)證支持
12 部署與維護(hù)
10 國(guó)際化和本地化
1.1 Go 安裝
6.2 Go如何使用session
5.6 NOSQL數(shù)據(jù)庫操作
6.5 小結(jié)
9.4 避免SQL注入
12.1 應(yīng)用日志
4.2 驗(yàn)證表單的輸入
10.1 設(shè)置默認(rèn)地區(qū)
1.3 Go 命令
9.6 加密和解密數(shù)據(jù)
4.1 處理表單的輸入
4.4 防止多次遞交表單
11.3 Go怎么寫測(cè)試用例
8 Web服務(wù)
12.3 應(yīng)用部署
5.7 小結(jié)
12.5 小結(jié)
11 錯(cuò)誤處理,調(diào)試和測(cè)試
9.2 確保輸入過濾
14.2 Session支持
6.4 預(yù)防session劫持
12.4 備份和恢復(fù)
8.1 Socket編程
13.1 項(xiàng)目規(guī)劃
13.4 日志和配置設(shè)計(jì)
7.6 字符串處理
13.2 自定義路由器設(shè)計(jì)
6.3 session存儲(chǔ)
3.4 Go的http包詳解
8.2 WebSocket
10.3 國(guó)際化站點(diǎn)
7.5 文件操作
7.4 模板處理
9.1 預(yù)防CSRF攻擊
13.3 controller設(shè)計(jì)
2.6 interface
14.4 用戶認(rèn)證
2.3 流程和函數(shù)
附錄A 參考資料
11.1 錯(cuò)誤處理
9.5 存儲(chǔ)密碼
9.3 避免XSS攻擊
12.2 網(wǎng)站錯(cuò)誤處理
6 session和數(shù)據(jù)存儲(chǔ)
2.4 struct類型
3.3 Go如何使得Web工作
2.5 面向?qū)ο?/span>
3.1 Web工作方式
1.2 GOPATH與工作空間
2.1 你好,Go
9.7 小結(jié)
13.5 實(shí)現(xiàn)博客的增刪改
7.2 JSON處理
10.2 本地化資源
7.3 正則處理
2 Go語言基礎(chǔ)
5.1 database/sql接口
4.5 處理文件上傳
8.5 小結(jié)
4.3 預(yù)防跨站腳本
5.3 使用SQLite數(shù)據(jù)庫
14.7 小結(jié)
3.2 Go搭建一個(gè)Web服務(wù)器
2.7 并發(fā)
5 訪問數(shù)據(jù)庫
4 表單
3.5 小結(jié)
1.4 Go開發(fā)工具
11.4 小結(jié)
9 安全與加密
5.2 使用MySQL數(shù)據(jù)庫
4.6 小結(jié)
8.4 RPC

3.3 Go如何使得Web工作

前面小節(jié)介紹了如何通過Go搭建一個(gè)Web服務(wù),我們可以看到簡(jiǎn)單應(yīng)用一個(gè)net/http包就方便的搭建起來了。那么Go在底層到底是怎么做的呢?萬變不離其宗,Go的Web服務(wù)工作也離不開我們第一小節(jié)介紹的Web工作方式。

web工作方式的幾個(gè)概念

以下均是服務(wù)器端的幾個(gè)概念

Request:用戶請(qǐng)求的信息,用來解析用戶的請(qǐng)求信息,包括post、get、cookie、url等信息

Response:服務(wù)器需要反饋給客戶端的信息

Conn:用戶的每次請(qǐng)求鏈接

Handler:處理請(qǐng)求和生成返回信息的處理邏輯

分析http包運(yùn)行機(jī)制

如下圖所示,是Go實(shí)現(xiàn)Web服務(wù)的工作模式的流程圖

http://wiki.jikexueyuan.com/project/go-web-programming/images/3.3.http.png" alt="" />

圖3.9 http包執(zhí)行流程

  1. 創(chuàng)建Listen Socket, 監(jiān)聽指定的端口, 等待客戶端請(qǐng)求到來。

  2. Listen Socket接受客戶端的請(qǐng)求, 得到Client Socket, 接下來通過Client Socket與客戶端通信。

  3. 處理客戶端的請(qǐng)求, 首先從Client Socket讀取HTTP請(qǐng)求的協(xié)議頭, 如果是POST方法, 還可能要讀取客戶端提交的數(shù)據(jù), 然后交給相應(yīng)的handler處理請(qǐng)求, handler處理完畢準(zhǔn)備好客戶端需要的數(shù)據(jù), 通過Client Socket寫給客戶端。

這整個(gè)的過程里面我們只要了解清楚下面三個(gè)問題,也就知道Go是如何讓W(xué)eb運(yùn)行起來了

  • 如何監(jiān)聽端口?
  • 如何接收客戶端請(qǐng)求?
  • 如何分配handler?

前面小節(jié)的代碼里面我們可以看到,Go是通過一個(gè)函數(shù)ListenAndServe來處理這些事情的,這個(gè)底層其實(shí)這樣處理的:初始化一個(gè)server對(duì)象,然后調(diào)用了net.Listen("tcp", addr),也就是底層用TCP協(xié)議搭建了一個(gè)服務(wù),然后監(jiān)控我們?cè)O(shè)置的端口。

下面代碼來自Go的http包的源碼,通過下面的代碼我們可以看到整個(gè)的http處理過程:

func (srv *Server) Serve(l net.Listener) error {
    defer l.Close()
    var tempDelay time.Duration // how long to sleep on accept failure
    for {
        rw, e := l.Accept()
        if e != nil {
            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
                }
                log.Printf("http: Accept error: %v; retrying in %v", e, tempDelay)
                time.Sleep(tempDelay)
                continue
            }
            return e
        }
        tempDelay = 0
        c, err := srv.newConn(rw)
        if err != nil {
            continue
        }
        go c.serve()
    }
}

監(jiān)控之后如何接收客戶端的請(qǐng)求呢?上面代碼執(zhí)行監(jiān)控端口之后,調(diào)用了srv.Serve(net.Listener)函數(shù),這個(gè)函數(shù)就是處理接收客戶端的請(qǐng)求信息。這個(gè)函數(shù)里面起了一個(gè)for{},首先通過Listener接收請(qǐng)求,其次創(chuàng)建一個(gè)Conn,最后單獨(dú)開了一個(gè)goroutine,把這個(gè)請(qǐng)求的數(shù)據(jù)當(dāng)做參數(shù)扔給這個(gè)conn去服務(wù):go c.serve()。這個(gè)就是高并發(fā)體現(xiàn)了,用戶的每一次請(qǐng)求都是在一個(gè)新的goroutine去服務(wù),相互不影響。

那么如何具體分配到相應(yīng)的函數(shù)來處理請(qǐng)求呢?conn首先會(huì)解析request:c.readRequest(),然后獲取相應(yīng)的handler:handler := c.server.Handler,也就是我們剛才在調(diào)用函數(shù)ListenAndServe時(shí)候的第二個(gè)參數(shù),我們前面例子傳遞的是nil,也就是為空,那么默認(rèn)獲取handler = DefaultServeMux,那么這個(gè)變量用來做什么的呢?對(duì),這個(gè)變量就是一個(gè)路由器,它用來匹配url跳轉(zhuǎn)到其相應(yīng)的handle函數(shù),那么這個(gè)我們有設(shè)置過嗎?有,我們調(diào)用的代碼里面第一句不是調(diào)用了http.HandleFunc("/", sayhelloName)嘛。這個(gè)作用就是注冊(cè)了請(qǐng)求/的路由規(guī)則,當(dāng)請(qǐng)求uri為"/",路由就會(huì)轉(zhuǎn)到函數(shù)sayhelloName,DefaultServeMux會(huì)調(diào)用ServeHTTP方法,這個(gè)方法內(nèi)部其實(shí)就是調(diào)用sayhelloName本身,最后通過寫入response的信息反饋到客戶端。

詳細(xì)的整個(gè)流程如下圖所示:

http://wiki.jikexueyuan.com/project/go-web-programming/images/3.3.illustrator.png" alt="" />

圖3.10 一個(gè)http連接處理流程

至此我們的三個(gè)問題已經(jīng)全部得到了解答,你現(xiàn)在對(duì)于Go如何讓W(xué)eb跑起來的是否已經(jīng)基本了解呢?