欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Golang中基于HTTP協(xié)議的網(wǎng)絡(luò)服務(wù)

 更新時(shí)間:2023年04月13日 11:22:44   作者:鯤鵬飛九萬(wàn)里  
HTTP協(xié)議是基于TCP/IP協(xié)議棧的,并且它也是一個(gè)面向普通文本的協(xié)議。這篇文章主要詳細(xì)介紹了Golang中基于HTTP協(xié)議的網(wǎng)絡(luò)服務(wù),感興趣的小伙伴可以借鑒一下

一、HTTP協(xié)議的網(wǎng)絡(luò)服務(wù)

HTTP協(xié)議是基于TCP/IP協(xié)議棧的,并且它也是一個(gè)面向普通文本的協(xié)議。

只要搞清楚了HTTP請(qǐng)求的報(bào)文(報(bào)文的頭部(header)和主體(body))應(yīng)該包含的內(nèi)容,使用任何一個(gè)文本編譯器,就餓可以編寫一個(gè)完整的HTTP請(qǐng)求報(bào)文。

在這種情況下,直接使用net.Dial函數(shù),就可以。

使用net/http代碼包中的程序?qū)嶓w,可以更便捷的訪問(wèn)基于HTTP協(xié)議的網(wǎng)絡(luò)服務(wù)。其中最便捷的是使用http.Get函數(shù)。

1.1 使用http.Get函數(shù)訪問(wèn)HTTP協(xié)議的網(wǎng)絡(luò)服務(wù)

package main

import (
	"fmt"
	"net/http"
)

func main() {
	url1 := "http://www.google.cn/"
	fmt.Printf("Send request to %q with method GET ... \n", url1)
	response1, err := http.Get(url1)
	if err != nil {
		fmt.Printf("request sending error: %v\n", err)
	}
	defer response1.Body.Close()
	line1 := response1.Proto + " " + response1.Status
	fmt.Printf("The first line of response: \n %s \n", line1)
}

http.Get函數(shù)會(huì)返回兩個(gè)結(jié)果值:

  • 第一個(gè)結(jié)果值的類型是*http.Response,它是網(wǎng)絡(luò)服務(wù)給我們傳回來(lái)的響應(yīng)內(nèi)容的結(jié)構(gòu)化表示。
  • 第二個(gè)結(jié)果值是error類型。它代表了在創(chuàng)建和發(fā)送HTTP請(qǐng)求,以及接受和解析HTTP響應(yīng)的過(guò)程中可能發(fā)生的錯(cuò)誤。

http.Get函數(shù)內(nèi)部會(huì)使用缺省的HTTP客戶端,并調(diào)用它的Get方法以完成功能。缺省客戶端類型是*http.Client,由公開變量DefaultClient代表。

1.2 使用缺省客戶端DefaultClient(類型為*http.Client )

package main

import (
	"fmt"
	"net/http"
)

func main() {
	url1 := "http://www.google.cn/"
	fmt.Printf("Send request to %q with method GET ... \n", url1)
	// response1, err := http.Get(url1)
	response1, err := http.DefaultClient.Get(url1)
	if err != nil {
		fmt.Printf("request sending error: %v\n", err)
	}
	defer response1.Body.Close()
	line1 := response1.Proto + " " + response1.Status
	fmt.Printf("The first line of response: \n %s \n", line1)
}

它的基本類型(http.Client)可以開箱即用。

1.3 使用http.Client訪問(wèn)HTTP協(xié)議的網(wǎng)絡(luò)服務(wù)

package main

import (
	"fmt"
	"net/http"
)

func main() {
	url1 := "http://www.google.cn/"
	fmt.Printf("Send request to %q with method GET ... \n", url1)
	// response1, err := http.Get(url1)
	// response1, err := http.DefaultClient.Get(url1)
	var oneClient http.Client
	response1, err := oneClient.Get(url1)
	if err != nil {
		fmt.Printf("request sending error: %v\n", err)
	}
	defer response1.Body.Close()
	line1 := response1.Proto + " " + response1.Status
	fmt.Printf("The first line of response: \n %s \n", line1)
}

http.Client是一個(gè)結(jié)構(gòu)體類型,并且它包含的字段是公開的。之所以該類型的零值仍然可以使用,是因?yàn)樗倪@些字段要么存在著響應(yīng)的缺省值,要么其零值直接可以使用,且代表著特定的含義。

二、http.Client中的Transport字段

http.Client類型中的Transport字段代表著:向網(wǎng)絡(luò)服務(wù)發(fā)送HTTP請(qǐng)求,并從網(wǎng)絡(luò)服務(wù)接收HTTP響應(yīng)的操作過(guò)程。

Transport字段的RoundTrip方法實(shí)現(xiàn)單次HTTP事務(wù)(或者說(shuō)基于HTTP協(xié)議的單詞交互)需要的所有步驟。

 Transport 字段是http.RoundTrip接口類型,它有一個(gè)缺省值,這個(gè)缺省值的變量名為DefaultTransport。DefaultTransport的實(shí)際類型為*http.Transport,*http.Transport可以被復(fù)用,并且是線程安全的。

如果沒(méi)有顯式的為http.Client中的Transport字段賦值,這個(gè)Client就會(huì)直接使DefaultTransport。

 http.Client中的Timeout字段,代表前面所說(shuō)的單詞HTTP事務(wù)的超時(shí)時(shí)間,它time.Duration類型,它的零值是可用的,用于表示沒(méi)有設(shè)置超時(shí)時(shí)間。

(1)http.Transport類型中的DialContext字段

http.Transport類型,在內(nèi)部使用一個(gè)net.Dialer類型的值,并且會(huì)把該值的Timeout字段的值,設(shè)定為30秒。

也就是說(shuō),這個(gè)Dialer值如果在30秒內(nèi)還沒(méi)有建立好網(wǎng)絡(luò)連接,那么就會(huì)被判定為操作超時(shí)。

在DefaultTransport的值被初始化的時(shí)候,這樣的Dialer值的DialContext方法會(huì)被賦給前者DialContext字段:

var DefaultTransport RoundTripper = &Transport{
	Proxy: ProxyFromEnvironment,
	DialContext: defaultTransportDialContext(&net.Dialer{
		Timeout:   30 * time.Second,
		KeepAlive: 30 * time.Second,
	}),
	ForceAttemptHTTP2:     true,
	MaxIdleConns:          100,
	IdleConnTimeout:       90 * time.Second,
	TLSHandshakeTimeout:   10 * time.Second,
	ExpectContinueTimeout: 1 * time.Second,
}

func defaultTransportDialContext(dialer *net.Dialer) func(context.Context, string, string) (net.Conn, error) {
	return dialer.DialContext
}

KeepAlive的背后是一種針對(duì)網(wǎng)絡(luò)連接(更確切地說(shuō),是TCP連接)的存活探測(cè)機(jī)制。它的值用于表示每隔多長(zhǎng)時(shí)間發(fā)送一次探測(cè)包。當(dāng)該值不大于0時(shí),則表示不開啟這種機(jī)制。

DefaultTransport會(huì)把這個(gè)字段的值設(shè)定為30秒。

(2)http.Transport類型中的其它字段

一些是關(guān)于超時(shí)操作

  • IdleConnTimeout:含義是空閑的連接在多久之后就應(yīng)該關(guān)閉。

 DefaultTransport 會(huì)把該字段的值設(shè)定為90秒。

如果該值為0,那么就表示不關(guān)閉空閑連接。注意,這樣可能會(huì)造成資源的泄露。

  • ResponseHeaderTimeout:含義是,從客戶端把請(qǐng)求完全遞交給操作系統(tǒng)到從操作系統(tǒng)那里接收到響應(yīng)報(bào)文頭到最長(zhǎng)時(shí)長(zhǎng)。

 DefaultTransport并沒(méi)有設(shè)定該字段的值。

  •  ExpectContinueTimeout:含義是,在客戶端提交了請(qǐng)求報(bào)文頭之后,等待接收第一個(gè)響應(yīng)報(bào)文頭的最長(zhǎng)時(shí)間。

 DefaultTransport 把該字段的值設(shè)定為1秒。

在客戶端想要使用HTTP的“POST”方法把一個(gè)很大的報(bào)文體發(fā)送給服務(wù)端的時(shí)候,它可以先通過(guò)發(fā)送一個(gè)包含了“Expect: 100-continue”的請(qǐng)求報(bào)文頭,來(lái)詢問(wèn)服務(wù)端是否愿意接受這個(gè)大報(bào)文體。這個(gè)字段就是用于設(shè)定在這種情況下的超時(shí)時(shí)間的。

注意,如果該字段的值不大于0,那么無(wú)論多大的請(qǐng)求報(bào)文體都將會(huì)被立即發(fā)送出去。

TLSHandshakeTimeout:TLS是Transport Layer Security 的縮寫,可以被翻譯為傳輸層安全。這個(gè)字段代表了基于TLS協(xié)議的連接在被建立時(shí)的握手階段的超時(shí)時(shí)間。

DefaultTransport 把該字段的值設(shè)置為10秒。

若該值為0,則表示對(duì)這個(gè)值不設(shè)限。

一些與IdleConnTimeout相關(guān)的字段值

  • MaxIdleConns:用于控制訪問(wèn)所有主機(jī)的最大空閑連接。如果為0,不做限制。

DefaultTransport 把MaxIdleConns設(shè)定為100。

MaxIdleConns字段只會(huì)對(duì)空閑連接的總數(shù)做出限定。

  • MaxIdleConnsPerHost: 控制Transport值訪問(wèn)每一個(gè)網(wǎng)絡(luò)服務(wù)的最大空閑連接數(shù)。如果為0,將使用缺省值2, 這個(gè)缺省值由DefaultMaxIdleConnsPerHost所代表。

也就是說(shuō),默認(rèn)情況下,對(duì)于某一個(gè)Transport值訪問(wèn)的每一個(gè)網(wǎng)絡(luò)服務(wù),它的空閑連接數(shù)都最多只能由兩個(gè)。

  • MaxConnsPerHost:針對(duì)某一個(gè)Transport值訪問(wèn)的每一個(gè)網(wǎng)絡(luò)服務(wù)的最大連接數(shù),不論這些連接是否是空閑的。

該字段沒(méi)有缺省值,零值表示不限定。

MaxIdleConns和MaxIdleConnsPerHost兩個(gè)與空閑連接數(shù)有關(guān)的字段的值應(yīng)該是聯(lián)動(dòng)的,所以,有時(shí)需要根據(jù)實(shí)際情況定制它們,可以參考DefaultTransport變量的聲明。

三、為什么會(huì)出現(xiàn)空閑的連接

3.1 空閑連接的產(chǎn)生

HTTP協(xié)議有一個(gè)請(qǐng)求報(bào)文頭,叫做“Connection”。在HTTP協(xié)議的1.1 版本中,這個(gè)報(bào)文頭的值默認(rèn)是“keep-alive”。

在這種情況下,網(wǎng)絡(luò)連接都是持久連接,它們會(huì)在當(dāng)前的HTTP事務(wù)完成后仍然保持著連通性,因此是可以被復(fù)用的。

連接的可復(fù)用,帶來(lái)兩種可能:

  • 一種可能是,針對(duì)同一個(gè)網(wǎng)絡(luò)服務(wù),有新的HTTP請(qǐng)求被提交,該連接被再次使用。
  • 另一種可能是,不再有對(duì)該網(wǎng)絡(luò)服務(wù)的HTTP請(qǐng)求,該連接被閑置。(產(chǎn)生空閑的連接)

后一種情況就產(chǎn)生了空閑連接。另外,如果分配給某一個(gè)網(wǎng)絡(luò)服務(wù)的連接過(guò)多的話,也可能會(huì)導(dǎo)致空閑連接的產(chǎn)生。因?yàn)槊恳粋€(gè)新遞交的HTTP請(qǐng)求,都只會(huì)征用一個(gè)空閑的連接。所以,為空閑連接設(shè)定限制,在大多數(shù)情況下都是很有必要的,也是需要斟酌的。

3.2 杜絕空閑連接的產(chǎn)生

如果想徹底杜絕空閑連接的產(chǎn)生,那么可以在初始化的時(shí)候,把它的DisableKeepAlives字段的值設(shè)定為true。這時(shí),HTTP請(qǐng)求的“Connection”報(bào)文頭的值就會(huì)被設(shè)置為“close”。這會(huì)告訴網(wǎng)絡(luò)服務(wù),這個(gè)網(wǎng)絡(luò)連接不必保持,當(dāng)前的HTTP事務(wù)完成后就可以斷開它。

如此一來(lái),每當(dāng)一個(gè)HTTP請(qǐng)求被遞交時(shí),就會(huì)產(chǎn)生一個(gè)新的網(wǎng)絡(luò)連接。這樣做會(huì)明顯地加重網(wǎng)絡(luò)服務(wù)以及客戶端的負(fù)載。所以,在一般情況下,我們都不要去設(shè)置這個(gè)DisableKeepAlive字段。

在net.Dialer類型中,也有一個(gè)看起來(lái)很相似的字段KeepAlive。不過(guò),它與前面所說(shuō)的HTTP 持久連接不是一個(gè)概念,KeepAlive是直接作用在底層的socket上的。

KeepAlive的背后是一種針對(duì)網(wǎng)絡(luò)連接(更確切地說(shuō),是TCP連接)的存活探測(cè)機(jī)制。它的值用于表示每隔多長(zhǎng)時(shí)間發(fā)送一次探測(cè)包。當(dāng)該值不大于0時(shí),則表示不開啟這種機(jī)制。DefaultTransport會(huì)把這個(gè)字段的值設(shè)定為30秒。

四、http.Server

http.Server類型與http.Client相對(duì)應(yīng)。http.Server代表的是基于HTTP協(xié)議的服務(wù)端,或者網(wǎng)絡(luò)服務(wù)。

4.1 http.Server類型的ListenAndServe方法

http.Server類型的ListenAndServe方法的功能是:監(jiān)聽一個(gè)基于TCP協(xié)議的網(wǎng)絡(luò)地址,并對(duì)接收到的HTTP請(qǐng)求進(jìn)行處理。

  • 這個(gè)方法默認(rèn)會(huì)開啟針對(duì)網(wǎng)絡(luò)連接的存活探測(cè)機(jī)制,以保證連接是持久的。
  • 同時(shí),該方法會(huì)一直執(zhí)行,直到有嚴(yán)重的錯(cuò)誤發(fā)生或被外界關(guān)掉。

當(dāng)被外界關(guān)掉時(shí),它會(huì)返回一個(gè)由http.ErrServerClosed變量代表的錯(cuò)誤值。

4.2 ListenAndServe方法主要做的事情

func (srv *Server) ListenAndServe() error {
	if srv.shuttingDown() {
		return ErrServerClosed
	}
	addr := srv.Addr
	if addr == "" {
		addr = ":http"
	}
	ln, err := net.Listen("tcp", addr)
	if err != nil {
		return err
	}
	return srv.Serve(ln)
}

ListenAndServe方法主要會(huì)做下面的事情:

  • 檢查當(dāng)前的http.Server類型的值的Addr字段。

該字段的值代表了當(dāng)前的網(wǎng)絡(luò)服務(wù)需要使用的網(wǎng)絡(luò)地址。即:IP地址和端口號(hào)。如果這個(gè)字段的值為空字符串,那么就用":http"代替。

也就是說(shuō),使用任何可以代表本機(jī)的域名和IP地址,并且端口號(hào)為80.

  • 通過(guò)調(diào)用net.Listen函數(shù)在已確定的網(wǎng)絡(luò)地址上啟動(dòng)基于TCP協(xié)議的監(jiān)聽。
  • 檢查net.Listen 函數(shù)返回的錯(cuò)誤值。

如果該錯(cuò)誤值不為nil,那么就直接返回該值。否則,通過(guò)調(diào)用當(dāng)前值的Serve方法準(zhǔn)備接受和處理將要到來(lái)的HTTP請(qǐng)求。

4.3 (衍生問(wèn)題)net.Listen 函數(shù)都做了哪些事情

net.Listen函數(shù)做的事情:

  • 解析參數(shù)值中包含的網(wǎng)絡(luò)地址隱含的IP地址和端口號(hào);
  • 根據(jù)給定的網(wǎng)絡(luò)協(xié)議,確定監(jiān)聽的方法,并開始進(jìn)行監(jiān)聽;

這里還可以延伸到net.socket函數(shù),以及socket相關(guān)的知識(shí)。

4.4 (衍生問(wèn)題)http.Server類型的Serve方法是怎么接受和處理HTTP請(qǐng)求的

在一個(gè)for循環(huán)中,網(wǎng)絡(luò)監(jiān)聽的Accept方法會(huì)被不斷的調(diào)用,

	for {
		rw, err := l.Accept()
  }

該方法會(huì)返回兩個(gè)結(jié)果值:

  • 第一個(gè)結(jié)果值是net.Conn 類型,代表包含了新到來(lái)的HTTP請(qǐng)求的網(wǎng)絡(luò)連接;
  • 第二個(gè)結(jié)果值是error類型值,代表可能發(fā)生的錯(cuò)誤。

如果錯(cuò)誤不為nil,除非它代表了一個(gè)暫時(shí)性的錯(cuò)誤,否則循環(huán)都會(huì)被終止。如果是暫時(shí)性的錯(cuò)誤,那么循環(huán)的下一次迭代將會(huì)在一段時(shí)間之后開始執(zhí)行。

如果這里的Accept方法沒(méi)有返回非nil的錯(cuò)誤值,那么這里的程序?qū)?huì)把它的第一個(gè)結(jié)果值包裝成一個(gè)*http.conn類型的值,然后通過(guò)在新的goroutine中調(diào)用這個(gè)*http.conn 類型值的serve方法,來(lái)對(duì)當(dāng)前的HTTP請(qǐng)求進(jìn)行處理。

HTTP請(qǐng)求相關(guān)的,更多的衍生問(wèn)題:

  • 這個(gè)*http.conn類型值的狀態(tài)有幾種,分別代表著處理的哪個(gè)階段?
  • 處理的過(guò)程中會(huì)用到哪些讀取器和寫入器,它們的作用分別是什么?
  • 這里的程序是怎么調(diào)用我們自定義的處理函數(shù)的?

五、思考:怎么優(yōu)雅地停止基于HTTP協(xié)議的網(wǎng)絡(luò)服務(wù)程序?

srv.Shutdown(context.Background()) 的方式停止服務(wù),通過(guò)RegisterOnShutdown可添加服務(wù)停止時(shí)的調(diào)用。

以上就是Golang中基于HTTP協(xié)議的網(wǎng)絡(luò)服務(wù)的詳細(xì)內(nèi)容,更多關(guān)于Golang HTTP協(xié)議的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Go設(shè)計(jì)模式之代理模式圖文詳解

    Go設(shè)計(jì)模式之代理模式圖文詳解

    這篇文章將通過(guò)圖文講解給大家詳細(xì)的介紹一下Go代理模式,代理模式是一種結(jié)構(gòu)型設(shè)計(jì)模式,代理控制著對(duì)于原對(duì)象的訪問(wèn), 并允許在將請(qǐng)求提交給對(duì)象前后進(jìn)行一些處理,感興趣的同學(xué)跟著小編一起來(lái)看看吧
    2023-07-07
  • 我為什么喜歡Go語(yǔ)言(簡(jiǎn)潔的Go語(yǔ)言)

    我為什么喜歡Go語(yǔ)言(簡(jiǎn)潔的Go語(yǔ)言)

    從2000年至今,也寫了11年代碼了,期間用過(guò)VB、Delphi、C#、C++、Ruby、Python,一直在尋找一門符合自己心意和理念的語(yǔ)言。我很在意寫代碼時(shí)的手感和執(zhí)行的效率,所以在Go出現(xiàn)之前一直沒(méi)有找到
    2014-10-10
  • go語(yǔ)言中range用法

    go語(yǔ)言中range用法

    這篇文章主要介紹了go語(yǔ)言中range用法,實(shí)例分析了Go語(yǔ)言中range的功能及使用技巧,需要的朋友可以參考下
    2015-03-03
  • 一文解析 Golang sync.Once 用法及原理

    一文解析 Golang sync.Once 用法及原理

    這篇文章主要介紹了一文解析 Golang sync.Once 用法及原理,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下
    2022-08-08
  • Go流程控制代碼詳解

    Go流程控制代碼詳解

    這篇文章主要詳細(xì)介紹了Go流程控制,文章通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值 ,需要的朋友可以參考下
    2023-04-04
  • GO使用阿里云,解決go get下載項(xiàng)目慢或無(wú)法下載的情況

    GO使用阿里云,解決go get下載項(xiàng)目慢或無(wú)法下載的情況

    這篇文章主要介紹了GO使用阿里云,解決go get下載項(xiàng)目慢或無(wú)法下載的情況,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-01-01
  • 一文詳解Golang?定時(shí)任務(wù)庫(kù)?gron?設(shè)計(jì)和原理

    一文詳解Golang?定時(shí)任務(wù)庫(kù)?gron?設(shè)計(jì)和原理

    這篇文章主要介紹了一文詳解Golang?定時(shí)任務(wù)庫(kù)?gron?設(shè)計(jì)和原理,gron是一個(gè)比較小巧、靈活的定時(shí)任務(wù)庫(kù),可以執(zhí)行定時(shí)的、周期性的任務(wù)。gron提供簡(jiǎn)潔的、并發(fā)安全的接口
    2022-08-08
  • Go創(chuàng)建Grpc鏈接池實(shí)現(xiàn)過(guò)程詳解

    Go創(chuàng)建Grpc鏈接池實(shí)現(xiàn)過(guò)程詳解

    這篇文章主要為大家介紹了Go創(chuàng)建Grpc鏈接池實(shí)現(xiàn)過(guò)程詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-03-03
  • 解決Golang中g(shù)oroutine執(zhí)行速度的問(wèn)題

    解決Golang中g(shù)oroutine執(zhí)行速度的問(wèn)題

    這篇文章主要介紹了解決Golang中g(shù)oroutine執(zhí)行速度的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2021-05-05
  • Golang接入釘釘通知的示例代碼

    Golang接入釘釘通知的示例代碼

    本文主要介紹了Golang接入釘釘通知的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-08-08

最新評(píng)論