日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

GO WBE学习笔记

發(fā)布時間:2023/12/20 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 GO WBE学习笔记 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

GoWeb學(xué)習(xí)筆記

學(xué)習(xí)的資料來自楊旭老師在B站的視頻

文章目錄

  • GoWeb學(xué)習(xí)筆記
    • 創(chuàng)建第一個Web程序(網(wǎng)頁輸出HelloWorld)
      • HadleFunc源碼
        • 使用HadleFunc,并創(chuàng)建內(nèi)置函數(shù)的形式創(chuàng)建訪問函數(shù)
        • 使用HadleFunc,并調(diào)用外部函數(shù)的形式創(chuàng)建訪問函數(shù)
      • 創(chuàng)建訪問監(jiān)聽和服務(wù)
        • http.ListenAndServe源碼
        • http.Server源碼(去除了源碼中的注釋)
          • 使用http.ListenAndServe創(chuàng)建監(jiān)聽和服務(wù)
          • 使用http.Server創(chuàng)建監(jiān)聽和服務(wù)
        • 整合實現(xiàn)
          • 直接創(chuàng)建
          • 通過外部函數(shù)和使用http.Server實現(xiàn)
      • http.Handle源碼
        • 使用http.Handle創(chuàng)建一個Hello World
        • 注意
      • Go語言的五個內(nèi)置Handler
      • HTTP消息
        • Request(請求)
        • FORM字段
      • 上傳文件
        • POST請求-JSON BODY
      • ResponseWriter
        • 內(nèi)置的Response
        • 內(nèi)置的Response

創(chuàng)建第一個Web程序(網(wǎng)頁輸出HelloWorld)

在go語言中創(chuàng)建一個網(wǎng)頁中輸出的HelloWorld,需要先創(chuàng)建一個訪問的函數(shù),然后指定相應(yīng)的監(jiān)聽和服務(wù)

HadleFunc源碼

func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {DefaultServeMux.HandleFunc(pattern, handler) }

使用HadleFunc,并創(chuàng)建內(nèi)置函數(shù)的形式創(chuàng)建訪問函數(shù)

//HandleFunc一共有兩個參數(shù),第一個參數(shù)是訪問路徑,第二個參數(shù)是路由函數(shù) http.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) {writer.Write([]byte("Hello World!")) })

使用HadleFunc,并調(diào)用外部函數(shù)的形式創(chuàng)建訪問函數(shù)

//自定義的外部函數(shù) func MyHandleFunc(w http.ResponseWriter,r *http.Request){w.Write([]byte("MyHandleFunc")) }func main(){//調(diào)用函數(shù)http.HandleFunc("/myHandleFunc",MyHandleFunc) }

創(chuàng)建訪問監(jiān)聽和服務(wù)

創(chuàng)建訪問監(jiān)聽和服務(wù)有兩種方式,一個是調(diào)用http.ListenAndServe方法,需要配置兩個參數(shù),另一個是調(diào)用http.Server,這種方式需要自定http.Server提供的參數(shù),相對于http.ListenAndServe,這種方式更加靈活

http.ListenAndServe源碼

func ListenAndServe(addr string, handler Handler) error {server := &Server{Addr: addr, Handler: handler}return server.ListenAndServe() }

http.Server源碼(去除了源碼中的注釋)

type Server struct {Addr stringHandler Handler TLSConfig *tls.ConfigReadTimeout time.DurationReadHeaderTimeout time.DurationWriteTimeout time.DurationIdleTimeout time.DurationMaxHeaderBytes intTLSNextProto map[string]func(*Server, *tls.Conn, Handler)ConnState func(net.Conn, ConnState)ErrorLog *log.LoggerBaseContext func(net.Listener) context.ContextConnContext func(ctx context.Context, c net.Conn) context.ContextinShutdown atomicBool disableKeepAlives int32 nextProtoOnce sync.Once nextProtoErr error mu sync.Mutexlisteners map[*net.Listener]struct{}activeConn map[*conn]struct{}doneChan chan struct{}onShutdown []func() }
使用http.ListenAndServe創(chuàng)建監(jiān)聽和服務(wù)
//使用nil相當(dāng)與使用了go語言內(nèi)置的http.DefaultServeMux(多路復(fù)用器) //需要傳入兩個參數(shù),分別是訪問的地址和使用的訪問函數(shù) //當(dāng)使用localhost的時候可以寫為http.ListenAndServe(":8080",nil) http.ListenAndServe("localhost:8080",nil)
使用http.Server創(chuàng)建監(jiān)聽和服務(wù)
//等同于http.ListenAndServe,但是使用這種方式配置更加靈活,因為可以設(shè)置更多參數(shù)值server := http.Server{Addr: "localhost:8080",Handler: nil,}server.ListenAndServe()

整合實現(xiàn)

直接創(chuàng)建
//訪問路徑為localhost:8080 http.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) {writer.Write([]byte("Hello World!")) }) http.ListenAndServe("localhost:8080",nil)
通過外部函數(shù)和使用http.Server實現(xiàn)
//為了方便,寫了一個監(jiān)聽的函數(shù) func Listen(){server := http.Server{Addr: "localhost:8080",Handler: nil,}server.ListenAndServe() } //自定義的訪問函數(shù) func MyHandleFunc(w http.ResponseWriter,r *http.Request){//因為Write()函數(shù)的源碼為Write([]byte) (int, error),所以在輸出string類型的時候需要轉(zhuǎn)換w.Write([]byte("Hello World")) } func main(){http.HandleFunc("/myHandleFunc",MyHandleFunc)Listen() }

http.Handle源碼

func Handle(pattern string, handler Handler) { DefaultServeMux.Handle(pattern, handler) }

使用http.Handle創(chuàng)建一個Hello World

有http.Handle的源碼可以看出傳入的第二個參數(shù)為Handler,源碼如下:

type Handler interface {ServeHTTP(ResponseWriter, *Request) }

Handler是一個ServeHTTP類型的Type,所以傳入Handle的第二個參數(shù)也得是ServeHTTP類型的訪問函數(shù)

//自定義路由 type HelloHandler struct {}//自定義路由 type AboutHandler struct {} //定義訪問控制器 func (m *HelloHandler) ServeHTTP(w http.ResponseWriter ,r *http.Request) {w.Write([]byte("Hello World!")) } //定義訪問控制器 func (m *AboutHandler) ServeHTTP(w http.ResponseWriter ,r *http.Request) {w.Write([]byte("About!")) } func MyListen(){mh := HelloHandler{}ma := AboutHandler{}server := http.Server{Addr: ":8080",//不指定訪問路由器,從而達(dá)成通過訪問不同的路由參數(shù)而訪問不同的自定義路由器Handler: nil,}http.Handle("/hello",&mh)http.Handle("/about",&ma)server.ListenAndServe() }

注意

在上面使用Handle函數(shù)的時候是使用創(chuàng)建好的ServeHttp,我們也可以使用HandlerFunc來將創(chuàng)建的沒有繼承ServeHTTP的 路由轉(zhuǎn)化

//使用HandlerFunc將自定義的訪問控制轉(zhuǎn)換為一個Handler //HandlerFunc可以將某個具有適當(dāng)簽名的函數(shù)f適配成為一個Handler http.Handle("/my", http.HandlerFunc(MyHandleFunc))func MyHandleFunc(w http.ResponseWriter, r *http.Request) {w.Write([]byte("MyHandleFunc")) }

Go語言的五個內(nèi)置Handler

1.NotFoundHandler

返回一個handler,每個請求的相應(yīng)都是404 page not found

func NotFoundHandler() Handler { return HandlerFunc(NotFound) }

2.RedirectHandler

返回一個handler,把每一個請求按照狀態(tài)碼跳轉(zhuǎn)到指定的URL

常見的:StatusMovedPermanently、StatusFound、StatusSeeOther

func RedirectHandler(url string, code int) Handler {return &redirectHandler{url, code} }

3.StripPrefix

去前綴,返回一個handler,在指定的url中去掉前綴,然后調(diào)用另一個handler

func StripPrefix(prefix string, h Handler) Handler {if prefix == "" {return h}return HandlerFunc(func(w ResponseWriter, r *Request) {if p := strings.TrimPrefix(r.URL.Path, prefix); len(p) < len(r.URL.Path) {r2 := new(Request)*r2 = *rr2.URL = new(url.URL)*r2.URL = *r.URLr2.URL.Path = ph.ServeHTTP(w, r2)} else {NotFound(w, r)}}) }

4.TimeoutHandler

返回一個handler,在指定時間內(nèi)運行傳入的handler

func TimeoutHandler(h Handler, dt time.Duration, msg string) Handler {return &timeoutHandler{handler: h,body: msg,dt: dt,} }

5.FileServer

返回一個handler,使用基于root的文件系統(tǒng)來相應(yīng)請求

func FileServer(root FileSystem) Handler {return &fileHandler{root} } type FileSystem interface {Open(name string) (File, error) }

在使用時需要用到操作系統(tǒng)的文件系統(tǒng),所以一般交給下面的函數(shù)來用

type Dir string func (d Dir) Open(name string) (File, error) {if filepath.Separator != '/' && strings.ContainsRune(name, filepath.Separator) {return nil, errors.New("http: invalid character in file path")}dir := string(d)if dir == "" {dir = "."}fullName := filepath.Join(dir, filepath.FromSlash(path.Clean("/"+name)))f, err := os.Open(fullName)if err != nil {return nil, mapDirOpenError(err, fullName)}return f, nil }

HTTP消息

HTTP Request 和HTTP Response,他倆具有相同的結(jié)構(gòu),都有請求行,0個或者多個url,空行以及可選的消息體(body)

Request(請求)

在GO語言中Request是一個struct,代表了客戶端發(fā)送的HTTP請求消息(既可以代表客戶端的請求,也可以代表服務(wù)端的請求),可以通過Request的方法訪問請求中的Cookie、URL、User Agent等信息,源碼如下:

type Request struct {Method stringURL *url.URLProto string // "HTTP/1.0"ProtoMajor int // 1ProtoMinor int // 0Header HeaderBody io.ReadCloserGetBody func() (io.ReadCloser, error)ContentLength int64TransferEncoding []stringClose boolHost stringForm url.ValuesPostForm url.ValuesMultipartForm *multipart.FormTrailer HeaderRemoteAddr stringRequestURI stringTLS *tls.ConnectionStateCancel <-chan struct{}Response *Responsectx context.Context }

其中幾個重要的字段

1.URL

Request的URL字段就代表了請求行(請求信息第一行)里面的部分內(nèi)容,URL字段是指向url.URL類型的一個指針,url.URL是一個struct源碼如下:

type URL struct {Scheme stringOpaque string User *Userinfo Host string Path string RawPath string ForceQuery bool RawQuery string Fragment string RawFragment string }

URL的通用格式為:

scheme://[userinfo@]host/path[?query][#fragment]

不以斜杠開頭的URL被解釋為:

scheme:opaque[?query][#fragment]

URL Query

  • RawQuery提供實際查詢的字符串
  • 通過Request的Form字段

r.URL.Query()

該方法會提供查詢字符串對應(yīng)的map[string] [] string

URL Fragment

就是URL格式中的#后面的部分

當(dāng)請求從瀏覽器發(fā)出時,無法獲取到Fragment的值,因為在瀏覽器發(fā)送請求的時候會把Fragment去掉

部分客戶端工具發(fā)出的請求可以獲取到Fragment的值,例如HTTP客戶端包

2.Handler

請求和相應(yīng)的headers是通過Header類型來描述的,它是一個map類型,用來描述HTTP header里的Key-Value對。

Header map的key是string類型,value是[]string

設(shè)置key時會創(chuàng)建一個空的[]string作為value,value里面第一個元素就是新的header的值

如果是為指定的key添加一個新的header值的話,執(zhí)行append操作即可

3.Body

請求和相應(yīng)的bodies都是使用Body字段來表示的

Body是一個io.ReadCloser接口,一個Reader接口和一個Closer接口

Reader接口定義了一個Open方法,參數(shù)[]byte,返回byte的數(shù)量、可選的錯誤

Closer接口定義了一個Close方法:沒有參數(shù),返回可選的錯誤

讀取body的內(nèi)容,調(diào)用Body的Read方法

func getQuery(){http.HandleFunc("/query", func(writer http.ResponseWriter, request *http.Request) {//獲取URLurl := request.URL//調(diào)用query方法query := url.Query()//根據(jù)傳入的key值查詢相應(yīng)的數(shù)據(jù),返回全部值id := query["id"]//以日志的形式打印在控制臺log.Println(id)//根據(jù)傳入的key值返回第一個值name := query.Get("name")log.Println(name)}) }

4.Form、PostForm、MultipartForm

通過表單發(fā)送post請求

<form action="/index" method="post">用戶名<input type="text" name="name" />密碼<input type="password" name="password" /><input type="submit" /> </form>

action是發(fā)送請求對應(yīng)的服務(wù)器路徑,method是發(fā)送請求的方式,有post和get兩種,html表單里的數(shù)據(jù)會以name-value對的方式通過post請求發(fā)送出去。

name-value

通過psot發(fā)送的name-value數(shù)據(jù)對的格式通過表單的Content Type來指定,也就是表單里面的enctype屬性,在form表單中enctype的默認(rèn)屬性為application/x-www-form-urlencoded。

1.application/x-www-form-urlencoded

在這個屬性下,瀏覽器將會將表單數(shù)據(jù)編碼到查詢字符串里面,簡單的文本格式使用這種方式

2.multipart/form-data

在這種屬性下每一個name-value對都會被轉(zhuǎn)化為一個mime消息部分

每一個部分都有自己的Content Type和Content Disposition,在上傳文件的時候選用這個方式

3.text/plain

POST & GET

表單的method屬性可以設(shè)置post和get兩種屬性

1.GET

get請求沒有body,所有的數(shù)據(jù)都通過URL的name-value對來發(fā)送

2.POST

FORM字段

Resquest上的函數(shù)允許我們通過url或/和body中提取數(shù)據(jù),form里面的數(shù)據(jù)是key-value對

通常的做法是先調(diào)用ParseForm或ParseMultipartForm來解析Request,然后相應(yīng)的訪問Form、PostForm或MultipartForm字段

PostForm

PostForm只支持application/x-www-form-urlencoded,

func getForm(){http.HandleFunc("/process", func(writer http.ResponseWriter, request *http.Request) {request.ParseForm()//輸出到頁面fmt.Fprintln(writer,request.Form)//以日志的形式打印到控制臺log.Println(request.Form)}) }

前端代碼:

<form action="http://localhost:8080/process" method="post" >用戶名<input type="text" name="name" />密碼<input type="password" name="password" /><input type="submit" /> </form>

MultipartForm

使用MultipartForm的時候需要先調(diào)用ParseMultipartForm,ParseMultipartForm會在必要的時候調(diào)用ParseForm,里面需要傳入一個參數(shù)(讀取的數(shù)據(jù)長度,單位為字節(jié)),MultipartForm只包含表單的key-value對,返回類型是一個struct而不是map,這個struct里面包含兩個map,一個是你表單里面的數(shù)據(jù),另一個是文件

func getMultipart(){http.HandleFunc("/process", func(writer http.ResponseWriter, request *http.Request) {//參數(shù)為字節(jié),是上傳數(shù)據(jù)的長度request.ParseMultipartForm(1024)fmt.Fprintln(writer,request.MultipartForm)log.Println(request.MultipartForm)}) }

FormValue&PostFormValue

FormValue方法會返回form字段指定key對應(yīng)的第一個value,無需調(diào)用ParseForm和ParseMultipartForm

PostFormValue方法只能讀取PostForm

這兩種該方法都會調(diào)用ParseMultipartForm

當(dāng)你表單的enctype設(shè)置為multipart/form-data的時候,上面兩種方法無法獲取到表單的數(shù)據(jù)

上傳文件

首先form里面的enctype類型要設(shè)置為multipart/form-data

在GO語言中處理上傳文件的時候:

1.調(diào)用ParseMultiparForm方法

2.從file字段獲得FileHeadler,調(diào)用Open方法來獲得文件

3.可以使用ioutil.ReadAll函數(shù)將文件內(nèi)容讀取到byte切片里

func getFile(){http.HandleFunc("/process", func(writer http.ResponseWriter, request *http.Request) {request.ParseMultipartForm(1024)//因為file是一個map,也就是允許多個文件上傳,這里可以指定獲取那個文件,0代表第一個fileHeader := request.MultipartForm.File["uploaded"][0]file,err := fileHeader.Open()if err == nil {data,err := ioutil.ReadAll(file)if err != nil {fmt.Println(err)}fmt.Fprintln(writer,string(data))}}) }

方法2

func getFile2(){http.HandleFunc("/process", func(writer http.ResponseWriter, request *http.Request) {//返回第一個文件,當(dāng)只上傳一個文件的時候,這種方式更快file,_,err := request.FormFile("uploaded")if err == nil {data,err := ioutil.ReadAll(file)if err != nil {fmt.Println(err)}fmt.Fprintln(writer,string(data))}}) }

MultipartReader()

源碼如下:

func (r *Request) MultipartReader() (*multipart.Reader, error) {if r.MultipartForm == multipartByReader {return nil, errors.New("http: MultipartReader called twice")}if r.MultipartForm != nil {return nil, errors.New("http: multipart handled by ParseMultipartForm")}r.MultipartForm = multipartByReader

如果是multipart/form-data或multipart混合的POST請求,MultipartReader會返回一個MIME multipart reader,否則這返回一個error和nil

在使用中可以使用MultipartReader代替ParseMultipartForm來把請求的body作為stream進(jìn)行處理,它在處理的時候不是一次性處理整個表單數(shù)據(jù),而是檢查來自表單的值,然后每次處理一個

POST請求-JSON BODY

不是所有的post請求都來自form

在不同的客戶端框架下會以不同的方式對post請求編碼

例如jQuery通常使用application/x-www-form-urlencoded

Augular則是application/json,但是ParseForm方法無法處理application/json

ResponseWriter

從服務(wù)器向客戶端返回相應(yīng)需要使用ResponseWriter

ResponseWriter是一個接口,handler用它來返回相應(yīng),真正支撐ResponseWriter的幕后struct是一個非導(dǎo)出的http.response

寫入到ResponseWriter

ResponseWriter在底層實現(xiàn)的時候其實也是實現(xiàn)了一個指針

在ResponseWriter中,write方法接收一個byte切片作為參數(shù),然后把他寫入到HTTP相應(yīng)的Body里面。

如果Write方法被調(diào)用時,header里面沒有設(shè)定content type,那么數(shù)據(jù)的前512字節(jié)就會被用來監(jiān)測content type

func writeExample(w http.ResponseWriter,r *http.Request) {str := `<html><head><title>Go Web</title></head> <body><h1>Hello World</h1></body></html>`w.Write([]byte(str)) }

WriteHeader

WriteHeader方法接收一個整數(shù)類型(HTTP狀態(tài)碼)作為參數(shù),并把它作為HTTP響應(yīng)的狀態(tài)碼返回,如果這個方法沒有被顯示的調(diào)用,那么在第一次調(diào)用Write方法前會隱式的調(diào)用

當(dāng)WriteHeader被調(diào)用完后,仍然可以寫入到ResponseWriter,但是不能再修改header

func writeHeader(w http.ResponseWriter,r *http.Request) {w.WriteHeader(501)fmt.Fprintln(w,"66666666666666") }

Header

Header方法返回Headers的map。可以進(jìn)行修改,修改后的headers將會體現(xiàn)再返回給客戶端的HTTP響應(yīng)里

func headerExample(w http.ResponseWriter,r * http.Request) {//重定向訪問的請求w.Header().Set("location","http://www.baidu.com")//訪問請求的狀態(tài)碼w.WriteHeader(302) }

傳入json數(shù)據(jù)

type Post struct {User stringThreads []string }func jsonExample(w http.ResponseWriter , r *http.Request) {w.Header().Set("Content-Type","application/json")post := &Post{User: "張三",Threads: []string{"666","777","888"},}json,_:= json2.Marshal(post)w.Write(json) }

內(nèi)置的Response

1.NotFound函數(shù),包裝一個404狀態(tài)碼和一個額外的信息

2.ServeFile函數(shù),從文件系統(tǒng)提供文件,返回給請求者

3.ServeContent函數(shù),它可以把實現(xiàn)了io.ReadSeeker接口的任何東西里面的內(nèi)容返回給請求者,同時它還可以處理Range請求(范圍請求),如果只請求了資源的一部分內(nèi)容,那么ServeContent就可以如此響應(yīng)。而ServeFile或io.Copy則不行

4.Redirect函數(shù),告訴客戶端重定向到另一個URL
tp://www.baidu.com")
//訪問請求的狀態(tài)碼
w.WriteHeader(302)
}

傳入json數(shù)據(jù)```go type Post struct {User stringThreads []string }func jsonExample(w http.ResponseWriter , r *http.Request) {w.Header().Set("Content-Type","application/json")post := &Post{User: "張三",Threads: []string{"666","777","888"},}json,_:= json2.Marshal(post)w.Write(json) }

內(nèi)置的Response

1.NotFound函數(shù),包裝一個404狀態(tài)碼和一個額外的信息

2.ServeFile函數(shù),從文件系統(tǒng)提供文件,返回給請求者

3.ServeContent函數(shù),它可以把實現(xiàn)了io.ReadSeeker接口的任何東西里面的內(nèi)容返回給請求者,同時它還可以處理Range請求(范圍請求),如果只請求了資源的一部分內(nèi)容,那么ServeContent就可以如此響應(yīng)。而ServeFile或io.Copy則不行

4.Redirect函數(shù),告訴客戶端重定向到另一個URL

總結(jié)

以上是生活随笔為你收集整理的GO WBE学习笔记的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。