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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

request用法_Go 语言 Web 应用开发 第 04 课:高级模板用法

發(fā)布時(shí)間:2025/3/15 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 request用法_Go 语言 Web 应用开发 第 04 课:高级模板用法 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

在上一節(jié)課中,我們學(xué)習(xí)了標(biāo)準(zhǔn)庫(kù)中?text/template?包提供的文本模板引擎的邏輯控制、集合對(duì)象迭代和空白符號(hào)處理的用法。這節(jié)課,我們將學(xué)習(xí)標(biāo)準(zhǔn)庫(kù)模板引擎中的一些高級(jí)概念和使用方法,并將渲染結(jié)果轉(zhuǎn)換為 HTML。

模板中的作用域

和程序代碼中的作用域相似,在?text/template?包提供的文本模板引擎中也有作用域的概念。其實(shí)在上節(jié)課當(dāng)中,我們就已經(jīng)接觸過(guò) with 語(yǔ)句了,而這個(gè)語(yǔ)句就是模板作用域的最直接體現(xiàn)。

示例文件?template.go

package mainimport ("fmt""log""net/http""text/template"
)func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {// 創(chuàng)建模板對(duì)象并解析模板內(nèi)容tmpl, err := template.New("test").Parse(`{{$name1 := "alice"}}name1: {{$name1}}{{with true}} {{$name1 = "alice2"}} {{$name2 := "bob"}} name2: {{$name2}}{{end}}name1 after with: {{$name1}}`)if err != nil {
fmt.Fprintf(w, "Parse: %v", err)return
}// 調(diào)用模板對(duì)象的渲染方法
err = tmpl.Execute(w, nil)if err != nil {
fmt.Fprintf(w, "Execute: %v", err)return
}
})
log.Println("Starting HTTP server...")
log.Fatal(http.ListenAndServe("localhost:4000", nil))
}

在運(yùn)行這段代碼之前,我們首先需要注意幾點(diǎn):

  • 模板變量?name1?是在模板的全局作用域中定義的

  • 模板變量?name1?在 with 代碼塊中進(jìn)行的是單純的賦值操作,即?=?不是?:=

  • 模板變量?name2?是在 with 代碼塊的作用域中定義的

  • 嘗試運(yùn)行以上代碼可以在終端獲得以下結(jié)果:

    ? curl http://localhost:4000
    name1: alice
    name2: bob
    name1 after with: alice2

    可以看到,在進(jìn)入 with 代碼塊之前,name1?的值為 “alice”,但在 with 代碼塊中被修改成為了?alice2,這個(gè)賦值操作直接修改了在模板全局作用域中定義的模板變量?name1?的值。

    接下來(lái),我們對(duì)模板內(nèi)容做出如下修改(末尾追加了一行):

    示例文件?template_2.go

    ...tmpl, err := template.New("test").Parse(`{{$name1 := "alice"}}name1: {{$name1}}{{with true}} {{$name1 = "alice2"}} {{$name2 := "bob"}} name2: {{$name2}}{{end}}name1 after with: {{$name1}}name2 after with: {{$name2}}`)
    ...

    為了縮減篇幅并更好地專注于有變動(dòng)的部分,部分未改動(dòng)的代碼塊使用了 “…” 進(jìn)行替代

    如果嘗試運(yùn)行以上代碼,將在終端獲得以下錯(cuò)誤:

    ? curl http://localhost:4000
    Parse: template: test:10: undefined variable "$name2"

    模板引擎在解析階段就發(fā)現(xiàn)名為?$name2?的模板變量在 with 代碼塊之外是屬于未定義的,這和在程序代碼中操作一個(gè)超出作用域的變量是一致的。

    最后,我們?cè)賮?lái)觀察一下在作用域的規(guī)則下,對(duì)模板變量使用?=?和?:=?的區(qū)別(注意?{{$name1 := "alice2"}}?這一行):

    示例文件?template_3.go

    ...tmpl, err := template.New("test").Parse(`{{$name1 := "alice"}}name1: {{$name1}}{{with true}} {{$name1 := "alice2"}} {{$name2 := "bob"}} name1 in with: {{$name1}} name2: {{$name2}}{{end}}name1 after with: {{$name1}}`)
    ...

    為了縮減篇幅并更好地專注于有變動(dòng)的部分,部分未改動(dòng)的代碼塊使用了 “…” 進(jìn)行替代

    嘗試運(yùn)行以上代碼可以在終端獲得以下結(jié)果:

    ? curl http://localhost:4000
    name1: alice
    name1 in with: alice2
    name2: bob
    name1 after with: alice

    我們看到,當(dāng)我們?cè)谀0逯惺褂?:=?的時(shí)候,模板引擎會(huì)在當(dāng)前作用域內(nèi)新建一個(gè)同名的模板變量(等同于程序代碼中本地變量和全局變量的區(qū)別),在同個(gè)作用域內(nèi)對(duì)這個(gè)模板變量的操作都不會(huì)影響到其它作用域。

    除了 with 語(yǔ)句之外,if 語(yǔ)句和 range 語(yǔ)句也會(huì)在各自的代碼塊中形成一個(gè)局部的作用域,感興趣的同學(xué)可以基于示例代碼進(jìn)行修改和嘗試。

    模板函數(shù)

    模板函數(shù),顧名思義,就是像在程序代碼中的函數(shù)那樣,用于在運(yùn)行時(shí)調(diào)用的數(shù)據(jù)結(jié)構(gòu)。其實(shí)在上一節(jié)課中,我們就已經(jīng)介紹并使用過(guò)部分內(nèi)置模板函數(shù)了,還記得等式與不等式的判斷語(yǔ)句嗎?eq、ne?和?lt?等等,本質(zhì)上就是模板函數(shù),只是?text/template?包的文本模板引擎將它們內(nèi)置罷了。

    如果想要自定義模板函數(shù)并加入到模板對(duì)象中,可以通過(guò)?Funcs?方法:

    示例文件?template_func.go

    package mainimport ("fmt""log""net/http""text/template"
    )func main() {
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {// 創(chuàng)建模板對(duì)象并添加自定義模板函數(shù)tmpl := template.New("test").Funcs(template.FuncMap{"add": func(a, b int) int {return a + b
    },
    })// 解析模板內(nèi)容_, err := tmpl.Parse(`result: {{add 1 2}}`)if err != nil {
    fmt.Fprintf(w, "Parse: %v", err)return
    }// 調(diào)用模板對(duì)象的渲染方法
    err = tmpl.Execute(w, nil)if err != nil {
    fmt.Fprintf(w, "Execute: %v", err)return
    }
    })
    log.Println("Starting HTTP server...")
    log.Fatal(http.ListenAndServe("localhost:4000", nil))
    }

    Funcs?方法接受一個(gè)?template.FuncMap?類型的參數(shù),其用法和我們上節(jié)課講到的 map 類型根對(duì)象有異曲同工之妙,底層也是?map[string]interface{}?類型。

    在上面的代碼中,我們添加了一個(gè)名為?add?的函數(shù),其接受兩個(gè)?int?類型的參數(shù),返回相加后的結(jié)果。

    嘗試運(yùn)行以上代碼可以在終端獲得以下結(jié)果:

    ? curl http://localhost:4000
    result: 3

    通過(guò)這種方法,就可以向模板對(duì)象中添加更多的函數(shù)以滿足開發(fā)需要。標(biāo)準(zhǔn)庫(kù)的模板引擎還有許多其它用途的內(nèi)置模板函數(shù),可以通過(guò)用戶文檔查看。

    模板中的管道操作

    使用過(guò)類 Unix 操作系統(tǒng)的同學(xué)一定對(duì)管道操作(Pipeline)不會(huì)陌生,而這種便利的用法在?text/template?包的文本模板引擎中也可以實(shí)現(xiàn),連語(yǔ)法也是一模一樣的。

    示例文件?template_pipeline.go

    ...tmpl := template.New("test").Funcs(template.FuncMap{"add2": func(a int) int {return a + 2
    },
    })// 解析模板內(nèi)容_, err := tmpl.Parse(`result: {{add2 0 | add2 | add2}}`)
    ...

    為了縮減篇幅并更好地專注于有變動(dòng)的部分,部分未改動(dòng)的代碼塊使用了 “…” 進(jìn)行替代

    在這里,我們添加了一個(gè)名為?add2?的模板函數(shù),其作用就是返回?int?參數(shù)加 2 之后的結(jié)果。

    嘗試運(yùn)行以上代碼可以在終端獲得以下結(jié)果:

    ? curl http://localhost:4000
    result: 6

    我們?cè)谀0逯姓{(diào)用了三次?add2?函數(shù),其中兩次是通過(guò)管道操作,因此返回的結(jié)果為?0 + 2 + 2 + 2 = 6。

    有同學(xué)可能就會(huì)問了,這個(gè)?add2?函數(shù)只接受一個(gè)參數(shù),那如果模板函數(shù)接受兩個(gè)或者更多的參數(shù)還可以進(jìn)行管道操作嗎?答案當(dāng)然是肯定的。

    示例文件?template_pipeline_2.go

    ...tmpl := template.New("test").Funcs(template.FuncMap{"add": func(a, b int) int {return a + b
    },
    })// 解析模板內(nèi)容_, err := tmpl.Parse(`result: {{add 1 3 | add 2 | add 2}}`)
    ...

    為了縮減篇幅并更好地專注于有變動(dòng)的部分,部分未改動(dòng)的代碼塊使用了 “…” 進(jìn)行替代

    嘗試運(yùn)行以上代碼可以在終端獲得以下結(jié)果:

    ? curl http://localhost:4000
    result: 8

    感興趣的同學(xué)可以嘗試讓一個(gè)模板函數(shù)接收或者返回更多數(shù)量的參數(shù),看看是否仍舊可以進(jìn)行管道操作呢?

    模板復(fù)用

    當(dāng)程序代碼逐漸變得復(fù)雜的時(shí)候,就會(huì)希望通過(guò)抽象成獨(dú)立的函數(shù)或者方法來(lái)復(fù)用一部分代碼邏輯,在模板中也是一樣的道理。這一小節(jié),我們就來(lái)學(xué)習(xí)如何在?text/template?包的文本模板引擎中實(shí)現(xiàn)模板的復(fù)用。

    示例文件?template_reuse.go

    package mainimport ("fmt""log""net/http""strings""text/template"
    )func main() {
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {// 創(chuàng)建模板對(duì)象并添加自定義模板函數(shù)tmpl := template.New("test").Funcs(template.FuncMap{"join": strings.Join,
    })// 解析模板內(nèi)容_, err := tmpl.Parse(`{{define "list"}} {{join . ", "}}{{end}}Names: {{template "list" .names}}`)if err != nil {
    fmt.Fprintf(w, "Parse: %v", err)return
    }// 調(diào)用模板對(duì)象的渲染方法
    err = tmpl.Execute(w, map[string]interface{}{"names": []string{"Alice", "Bob", "Cindy", "David"},
    })if err != nil {
    fmt.Fprintf(w, "Execute: %v", err)return
    }
    })
    log.Println("Starting HTTP server...")
    log.Fatal(http.ListenAndServe("localhost:4000", nil))
    }

    閱讀以上代碼需要注意這幾點(diǎn):

  • 通過(guò)?Funcs?方法添加了名為?join?模板函數(shù),其實(shí)際上就是調(diào)用?strings.Join

  • 通過(guò)?define ""?的語(yǔ)法定義了一個(gè)非常簡(jiǎn)單的局部模板,即以根對(duì)象?.?作為參數(shù)調(diào)用?join?模板函數(shù)

  • 通過(guò)?template "" ?的語(yǔ)法,調(diào)用名為?list?的局部模板,并將?.names?作為參數(shù)傳遞進(jìn)去(傳遞的參數(shù)會(huì)成為局部模板的根對(duì)象)

  • 嘗試運(yùn)行以上代碼可以在終端獲得以下結(jié)果:

    ? curl http://localhost:4000
    Names: Alice, Bob, Cindy, David

    這個(gè)例子雖然簡(jiǎn)單,但也使用到了模板復(fù)用最核心的概念:定義、使用和傳參。

    從本地文件加載模板

    到目前為止,我們使用的模板內(nèi)容都是硬編碼在程序代碼中的,每次修改都需要重新編譯和運(yùn)行程序,這種方式不僅麻煩,而且當(dāng)模板數(shù)量特別多的時(shí)候也不利于進(jìn)行管理。因此,我們可以將模板內(nèi)容保存到本地文件,然后在程序中加載對(duì)應(yīng)的模板后進(jìn)行渲染,最后輸出結(jié)果到客戶端。

    示例文件?template_local.go

    package mainimport ("fmt""log""net/http""text/template"
    )func main() {// 創(chuàng)建模板對(duì)象并解析模板內(nèi)容tmpl, err := template.ParseFiles("template_local.tmpl")if err != nil {
    log.Fatalf("Parse: %v", err)
    }
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {// 調(diào)用模板對(duì)象的渲染方法
    err = tmpl.Execute(w, map[string]interface{}{"names": []string{"Alice", "Bob", "Cindy", "David"},
    })if err != nil {
    fmt.Fprintf(w, "Execute: %v", err)return
    }
    })
    log.Println("Starting HTTP server...")
    log.Fatal(http.ListenAndServe("localhost:4000", nil))
    }

    在這里,我們主要用到的函數(shù)是?template.ParseFiles,我們?cè)谕瑐€(gè)目錄創(chuàng)建一個(gè)名為?template_local.tmpl?的模板文件(文件后綴可以是任意的,一般在使用標(biāo)準(zhǔn)庫(kù)的模板引擎時(shí)習(xí)慣性地將文件后綴命名為?.tmpl?或?.tpl):

    {{range .names}}
    - {{.}}
    {{end}}

    嘗試運(yùn)行以上代碼可以在終端獲得以下結(jié)果:

    ? curl http://localhost:4000
    - Alice
    - Bob
    - Cindy
    - David

    值得注意的是,template.ParseFiles?接受的是變長(zhǎng)的參數(shù),因此我們可以同時(shí)指定一個(gè)或者多個(gè)模板文件。那么,怎么才能讓模板引擎知道我們想要進(jìn)行渲染的模板文件是哪一個(gè)呢?

    示例文件?template_local_2.go

    ...// 渲染指定模板的內(nèi)容
    err = tmpl.ExecuteTemplate(w, "template_local.tmpl", map[string]interface{}{"names": []string{"Alice", "Bob", "Cindy", "David"},
    })
    ...

    非常簡(jiǎn)單,只需要將?Execute?方法改成?ExecuteTemplate?就可以了,后者允許通過(guò)模板文件的名稱來(lái)指定具體渲染哪一個(gè)模板文件。在本例中,我們是通過(guò)本地文件加載模板的,因此模板的名稱就是文件名本身。

    html/template?與?text/template?的關(guān)聯(lián)與不同

    在 Web 應(yīng)用的開發(fā)過(guò)程中,服務(wù)端經(jīng)常需要向客戶端(通常為瀏覽器)輸出 HTML 內(nèi)容以構(gòu)成用戶可交互的頁(yè)面,我們依舊可以使用?text/template?包的模板引擎達(dá)到這個(gè)目的:

    示例文件?template_html.go

    package mainimport ("fmt""log""net/http""text/template"
    )func main() {
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {// 創(chuàng)建模板對(duì)象并解析模板內(nèi)容tmpl, err := template.New("test").Parse(`

    Heading 2

    Paragraph

    `)if err != nil {
    fmt.Fprintf(w, "Parse: %v", err)return
    }// 調(diào)用模板對(duì)象的渲染方法
    err = tmpl.Execute(w, nil)if err != nil {
    fmt.Fprintf(w, "Execute: %v", err)return
    }
    })
    log.Println("Starting HTTP server...")
    log.Fatal(http.ListenAndServe("localhost:4000", nil))
    }

    運(yùn)行以上代碼并通過(guò)瀏覽器訪問即可看到渲染后的 HTML 頁(yè)面:

    既然?text/template?包就可以達(dá)到渲染 HTML 頁(yè)面的目的,那為什么標(biāo)準(zhǔn)庫(kù)還要另外提供一個(gè)?html/template?包呢?按照官方的說(shuō)法,html/template?本身是一個(gè)?text/template?包的一層封裝,并在此基礎(chǔ)上專注于提供安全保障。作為使用者來(lái)說(shuō),最直觀的變化就是對(duì)所有的文本變量都進(jìn)行了轉(zhuǎn)義處理。

    怎么理解呢?我們來(lái)看下面這個(gè)例子。

    示例文件?template_xss.go

    package mainimport ("fmt""log""net/http""text/template"
    )func main() {
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {// 創(chuàng)建模板對(duì)象并解析模板內(nèi)容tmpl, err := template.New("test").Parse(`

    {{.content}}

    `)if err != nil {
    fmt.Fprintf(w, "Parse: %v", err)return
    }// 調(diào)用模板對(duì)象的渲染方法
    err = tmpl.Execute(w, map[string]interface{}{"content": "",
    })if err != nil {
    fmt.Fprintf(w, "Execute: %v", err)return
    }
    })
    log.Println("Starting HTTP server...")
    log.Fatal(http.ListenAndServe("localhost:4000", nil))
    }

    有一定 Web 開發(fā)基礎(chǔ)的同學(xué)肯定馬上就能看出來(lái),如果我們運(yùn)行這段代碼,將會(huì)導(dǎo)致俗稱的跨站腳本攻擊(Cross-site scripting, XSS),是最常見的 Web 應(yīng)用安全漏洞之一。

    如果想要避免此類攻擊,只需要將導(dǎo)入的包從?text/template?改成?html/template?就可以了。修改完成后,再運(yùn)行程序的話,我們只會(huì)看到被轉(zhuǎn)義之后的 JavaScript 腳本內(nèi)容,成功地避免了此類安全漏洞。

    反轉(zhuǎn)義

    我們剛剛學(xué)到,在渲染 HTML 內(nèi)容時(shí),正確的姿勢(shì)是使用?html/template?包進(jìn)行渲染操作,因?yàn)檫@個(gè)包可以為我們對(duì)可疑的內(nèi)容進(jìn)行轉(zhuǎn)義。這是一個(gè)優(yōu)點(diǎn),但從另一個(gè)角度講也是缺點(diǎn),因?yàn)樵谀承r(shí)候我們確實(shí)需要?jiǎng)討B(tài)地生成 HTML 內(nèi)容然后作為變量通過(guò)模板引擎進(jìn)行渲染。這時(shí),我們可以借助模板函數(shù),將我們確信安全的文本轉(zhuǎn)換為一個(gè)特殊類型?template.HTML,這樣模板引擎就知道不需要對(duì)其進(jìn)行轉(zhuǎn)義。

    示例文件?template_safe.go

    package mainimport ("fmt""html/template""log""net/http"
    )func main() {
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {// 創(chuàng)建模板對(duì)象并添加自定義模板函數(shù)tmpl := template.New("test").Funcs(template.FuncMap{"safe": func(s string) template.HTML {return template.HTML(s)
    },
    })// 解析模板內(nèi)容_, err := tmpl.Parse(`

    {{.content | safe}}

    `)if err != nil {
    fmt.Fprintf(w, "Parse: %v", err)return
    }// 調(diào)用模板對(duì)象的渲染方法
    err = tmpl.Execute(w, map[string]interface{}{"content": "Hello world!",
    })if err != nil {
    fmt.Fprintf(w, "Execute: %v", err)return
    }
    })
    log.Println("Starting HTTP server...")
    log.Fatal(http.ListenAndServe("localhost:4000", nil))
    }

    這里的核心部分就是?safe?模板函數(shù),其主要作用就是將?string?類型的字符串?s?轉(zhuǎn)換類型為?template.HTML?并返回。

    嘗試運(yùn)行以上代碼后,可以在瀏覽器獲得以下頁(yè)面:

    在一些 Web 應(yīng)用,我們確實(shí)會(huì)遇到需要將用戶輸入的內(nèi)容渲染為 HTML 格式,怎么樣才可以將任意文本安全地渲染成 HTML 且避免跨站腳本攻擊呢?幸運(yùn)地是,Go 語(yǔ)言社區(qū)已經(jīng)有人開源了一個(gè)名為?bluemonkey?的工具包,它可以幫助我們?cè)阡秩?HTML 時(shí)過(guò)濾掉所有潛在的不安全內(nèi)容,而非無(wú)腦地對(duì)所有字符進(jìn)行轉(zhuǎn)義。

    示例文件?template_bluemonkey.go

    package mainimport ("fmt""html/template""log""net/http""github.com/microcosm-cc/bluemonday"
    )func main() {p := bluemonday.UGCPolicy()
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {// 創(chuàng)建模板對(duì)象并添加自定義模板函數(shù)tmpl := template.New("test").Funcs(template.FuncMap{"sanitize": func(s string) template.HTML {return template.HTML(p.Sanitize(s))
    },
    })// 解析模板內(nèi)容_, err := tmpl.Parse(`

    {{.content | sanitize}}

    `)if err != nil {
    fmt.Fprintf(w, "Parse: %v", err)return
    }// 調(diào)用模板對(duì)象的渲染方法
    err = tmpl.Execute(w, map[string]interface{}{"content": `Google`,
    })if err != nil {
    fmt.Fprintf(w, "Execute: %v", err)return
    }
    })
    log.Println("Starting HTTP server...")
    log.Fatal(http.ListenAndServe("localhost:4000", nil))
    }

    嘗試運(yùn)行以上代碼后,可以在瀏覽器獲得以下頁(yè)面:

    從上圖中無(wú)法看出?bluemonkey?具體做了什么,我們可以通過(guò)終端查看:

    ? curl http://localhost:4000


    Google




    不難發(fā)現(xiàn),onblur="alert(secret)"?已經(jīng)被過(guò)濾掉了。這個(gè)工具包的功能非常強(qiáng)大,感興趣的同學(xué)可以自行查看文檔做更深入的研究。

    修改分隔符

    在本節(jié)課的最后,我們來(lái)快速學(xué)習(xí)一下如何修改模板的分隔符,因?yàn)闃?biāo)準(zhǔn)庫(kù)的模板引擎使用的花括號(hào)?{{?和?}}?和許多流行的前端框架有沖突(如 VueJS 和 AngularJS),所以知道怎么修改它們是非常有用的。

    示例文件?template_delims.go

    package mainimport ("fmt""log""net/http""text/template"
    )func main() {
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {// 創(chuàng)建模板對(duì)象并解析模板內(nèi)容tmpl, err := template.New("test").Delims("[[", "]]").Parse(`[[.content]]`)if err != nil {
    fmt.Fprintf(w, "Parse: %v", err)return
    }// 調(diào)用模板對(duì)象的渲染方法
    err = tmpl.Execute(w, map[string]interface{}{"content": "Hello world!",
    })if err != nil {
    fmt.Fprintf(w, "Execute: %v", err)return
    }
    })
    log.Println("Starting HTTP server...")
    log.Fatal(http.ListenAndServe("localhost:4000", nil))
    }

    在這里,我們通過(guò)?Delims?方法將它們分別修改為方括號(hào)?[[?和?]]。

    嘗試運(yùn)行以上代碼可以在終端獲得以下結(jié)果:

    ? curl http://localhost:4000
    Hello world!

    小結(jié)

    這節(jié)課,我們主要學(xué)習(xí)了標(biāo)準(zhǔn)庫(kù)中?text/template?包提供的文本模板引擎的作用域、管道操作、模板函數(shù)和模板復(fù)用,以及如何安全地渲染 HTML 內(nèi)容。

    下節(jié)課,我們將學(xué)習(xí)如何接收和處理 HTML 表單數(shù)據(jù)。

    ???

    點(diǎn)擊原文鏈接可以到 Go 語(yǔ)言中文網(wǎng)參與討論

    總結(jié)

    以上是生活随笔為你收集整理的request用法_Go 语言 Web 应用开发 第 04 课:高级模板用法的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

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